Class: Farce::Abstract::Molecule Abstract
- Inherits:
-
Object
- Object
- Farce::Abstract::Molecule
- Includes:
- Enumerable, Internal::Freeze::Tracked, Internal::Inspect, Internal::MarshalSupport::Initialize
- Defined in:
- lib/farce/abstract/molecule.rb
Overview
A record whose fields are independently atomic references.
Define a record class with Molecule.define, then read or assign its named fields.
Use each field's <name>_atom for updates, comparisons, and waits.
Operations on several fields are not a transaction or a consistent snapshot.
Direct Known Subclasses
Local::Molecule, Molecule, Strict::Molecule, Transaction::Molecule, Unshared::Molecule
Class Method Summary collapse
-
.atoms ⇒ Array<Symbol>
The atom accessor names in declaration order.
-
.compare_by_identity? ⇒ Boolean
The default comparison policy for new records.
-
.define(*fields, compare_by_identity: nil) ⇒ Class<Molecule>
Create a record class with readers, writers, and
<name>_atomaccessors. -
.members ⇒ Array<Symbol>
The field names in declaration order.
Instance Method Summary collapse
-
#atoms ⇒ Array<Symbol>
The atom accessor names in declaration order.
-
#compare_by_identity? ⇒ Boolean
Whether newly created atoms compare by identity instead of equality.
-
#each {|member, value| ... } ⇒ Array<Symbol>, Enumerator
(also: #each_pair)
Yield field names and current values in declaration order.
-
#each_atom {|name, atom| ... } ⇒ Array<Symbol>, Enumerator
Yield atom accessor names and atomic references in declaration order.
-
#each_member ⇒ Array<Symbol>, Enumerator
(also: #each_key)
Yield field names in declaration order.
-
#each_value ⇒ Array<Symbol>, Enumerator
Yield current field values in declaration order.
-
#freeze ⇒ self
Prevent field replacement and atom updates without freezing stored values.
-
#initialize(*input, compare_by_identity: nil, **attributes) ⇒ Molecule
constructor
Initialize fields by position or name.
-
#members ⇒ Array<Symbol>
The field names in declaration order.
Constructor Details
#initialize(*input, compare_by_identity: nil, **attributes) ⇒ Molecule
Initialize fields by position or name. A field may only be supplied once. Existing Atom instances are retained directly, preserving their policy.
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/farce/abstract/molecule.rb', line 122 def initialize(*input, compare_by_identity: nil, **attributes) raise ArgumentError, "too many positional values" if input.length > members.length @compare_by_identity = compare_by_identity.nil? ? self.class.compare_by_identity? : !!compare_by_identity # rubocop:disable Style/DoubleNegation @molecule_atoms = {} input.each_with_index { initialize_atom(members[_2], _1) } attributes.each { initialize_atom(_1, _2) } members.each { initialize_atom(it, nil) unless public_send(:"#{it}_atom") } @molecule_atoms.freeze super() end |
Class Method Details
.atoms ⇒ Array<Symbol>
Returns the atom accessor names in declaration order.
103 104 105 106 107 |
# File 'lib/farce/abstract/molecule.rb', line 103 def self.atoms return @atoms if defined?(@atoms) && @atoms return superclass.atoms if superclass.respond_to?(:atoms) EMPTY_ARRAY end |
.compare_by_identity? ⇒ Boolean
Returns the default comparison policy for new records.
77 |
# File 'lib/farce/abstract/molecule.rb', line 77 def self.compare_by_identity? = false |
.define(*fields, compare_by_identity: nil) ⇒ Class<Molecule>
Create a record class with readers, writers, and <name>_atom accessors.
Missing initial values default to nil. Generated classes may be subclassed.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/farce/abstract/molecule.rb', line 39 def self.define(*fields, compare_by_identity: nil) fields = fields.map(&:to_sym) names = fields.flat_map { [it, :"#{it}=", :"#{it}_atom", :"#{it}_atom="] } conflicts = names.any? do |name| next true if name == :freeze next false unless method_defined?(name) || private_method_defined?(name) instance_method(name).owner != Enumerable end if names.uniq.length != names.length || conflicts raise ArgumentError, "field names must be unique and must not override the molecule interface" end Class.new(self) do singleton_class.class_eval { undef define } unless nil.equal?(compare_by_identity) class_eval "def self.compare_by_identity? = #{(!!compare_by_identity).inspect}", __FILE__, __LINE__ - 1 end atoms = [] members = fields.map do |field| define_member(field) atoms << :"#{field}_atom" field end @atoms = Ractor.make_shareable(atoms.freeze) @members = Ractor.make_shareable(members.freeze) set_temporary_name("#{superclass.name}#{@members.inspect}") end end |
.members ⇒ Array<Symbol>
Returns the field names in declaration order.
110 111 112 113 114 |
# File 'lib/farce/abstract/molecule.rb', line 110 def self.members return @members if defined?(@members) && @members return superclass.members if superclass.respond_to?(:members) EMPTY_ARRAY end |
Instance Method Details
#atoms ⇒ Array<Symbol>
Returns the atom accessor names in declaration order.
158 |
# File 'lib/farce/abstract/molecule.rb', line 158 def atoms = self.class.atoms |
#compare_by_identity? ⇒ Boolean
Whether newly created atoms compare by identity instead of equality. Explicitly supplied atoms retain their own comparison policy.
155 |
# File 'lib/farce/abstract/molecule.rb', line 155 def compare_by_identity? = @compare_by_identity |
#each {|member, value| ... } ⇒ Array<Symbol>, Enumerator Also known as: each_pair
Yield field names and current values in declaration order.
167 168 169 170 |
# File 'lib/farce/abstract/molecule.rb', line 167 def each return enum_for(:each) unless block_given? members.each { yield it, public_send(it) } end |
#each_atom {|name, atom| ... } ⇒ Array<Symbol>, Enumerator
Yield atom accessor names and atomic references in declaration order.
177 178 179 180 |
# File 'lib/farce/abstract/molecule.rb', line 177 def each_atom return enum_for(:each_atom) unless block_given? atoms.each { yield it, public_send(it) } end |
#each_member ⇒ Array<Symbol>, Enumerator Also known as: each_key
Yield field names in declaration order.
184 185 186 187 |
# File 'lib/farce/abstract/molecule.rb', line 184 def each_member return enum_for(:each_member) unless block_given? members.each { yield it } end |
#each_value ⇒ Array<Symbol>, Enumerator
Yield current field values in declaration order.
192 193 194 195 |
# File 'lib/farce/abstract/molecule.rb', line 192 def each_value return enum_for(:each_value) unless block_given? members.each { yield public_send(it) } end |
#freeze ⇒ self
Prevent field replacement and atom updates without freezing stored values. Coordinate with writers before freezing. This is not a snapshot operation.
200 201 202 203 204 |
# File 'lib/farce/abstract/molecule.rb', line 200 def freeze return self if frozen? each_atom { |_, atom| atom.freeze } super end |
#members ⇒ Array<Symbol>
Returns the field names in declaration order.
161 |
# File 'lib/farce/abstract/molecule.rb', line 161 def members = self.class.members |