Class: Ditto::Entity
- Inherits:
-
Object
- Object
- Ditto::Entity
- Defined in:
- lib/ditto/entity.rb
Constant Summary collapse
- PROPS =
[ :mandatory, :unique, :related ].freeze
- @@entities =
Entities are stored in a hash keyed by entity name The contents are an array of Entity objects one for each version
Hash.new {|h,k| h[k] = []}
- @@instances =
Instances are stored in a hash keyed by entity name The contents are a hash (keyed by version) of arrays of instance hashes
Hash.new {|h,k| h[k] = Hash.new{|i,j|i[j] = []}}
Instance Attribute Summary collapse
-
#deps ⇒ Object
readonly
Returns the value of attribute deps.
-
#fields ⇒ Object
readonly
Returns the value of attribute fields.
-
#loc ⇒ Object
readonly
Returns the value of attribute loc.
-
#methods ⇒ Object
readonly
Returns the value of attribute methods.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Class Method Summary collapse
- .check_dm_versions(requirements) ⇒ Object
-
.dep_list(name, list, done) ⇒ Object
Compute dependencies recursively build a list in dependency sequence.
-
.find_entity_map(name, dataversion, type) ⇒ Object
Given the input data version get the right entity We assume all entity versions with same major work and take the highest.
-
.load_entities(filepath, verbose = 0) ⇒ Object
Load entities required by the instances.
-
.load_from_file(f) ⇒ Object
Errors discovered in here will be load/syntax errors Stack depth is just empirically determined! TODO WRITE A TEST!.
-
.load_instances(f, verbose = 0) ⇒ Object
Load data from YAML files into the in-memory representation return number of instances loaded if all OK.
- .reset ⇒ Object
-
.store_all(verbose = 0) ⇒ Object
Store the instances in dependency order.
Instance Method Summary collapse
-
#initialize(name, version, fields, methods) ⇒ Entity
constructor
Maps to the ‘entity’ DSL keyword Stack depth is just empirically determined! TODO WRITE A TEST!.
Constructor Details
#initialize(name, version, fields, methods) ⇒ Entity
Maps to the ‘entity’ DSL keyword Stack depth is just empirically determined! TODO WRITE A TEST!
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/ditto/entity.rb', line 26 def initialize name, version, fields, methods src = Thread.current.backtrace[3].split(':')[0..1] @name = name.to_sym @version = Gem::Version.new(version) rescue raise(Error.new(src), "#{name}: #{$!.}") @methods = methods @loc = src @deps = [] if @@entities.has_key?(@name) and @@entities[@name].any?{|e| e.version == @version} loc = @@entities[@name].select{|e| e.version == @version}.first.loc raise Error.new(src), "#{name}: previously defined at #{loc.join(':')}" end raise Error.new(src), "#{name}: entity fields must be a hash!" unless fields.kind_of? Hash @fields = Ditto.symbolize_keys fields nkey = 0 @fields.each do |field, props| symprops = Array(props).select{|p| p.is_a? Symbol} duffprops = symprops - PROPS unless duffprops.empty? raise Error.new(src), "#{name}: unknown properties: '#{duffprops.join(' ,')}'" end nkey += symprops.count(:unique) @deps << field if symprops.include? :related end @@entities[@name] << self end |
Instance Attribute Details
#deps ⇒ Object (readonly)
Returns the value of attribute deps.
21 22 23 |
# File 'lib/ditto/entity.rb', line 21 def deps @deps end |
#fields ⇒ Object (readonly)
Returns the value of attribute fields.
21 22 23 |
# File 'lib/ditto/entity.rb', line 21 def fields @fields end |
#loc ⇒ Object (readonly)
Returns the value of attribute loc.
21 22 23 |
# File 'lib/ditto/entity.rb', line 21 def loc @loc end |
#methods ⇒ Object (readonly)
Returns the value of attribute methods.
21 22 23 |
# File 'lib/ditto/entity.rb', line 21 def methods @methods end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
21 22 23 |
# File 'lib/ditto/entity.rb', line 21 def name @name end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
21 22 23 |
# File 'lib/ditto/entity.rb', line 21 def version @version end |
Class Method Details
.check_dm_versions(requirements) ⇒ Object
155 156 157 158 159 160 |
# File 'lib/ditto/entity.rb', line 155 def self.check_dm_versions requirements requirements.all? do |klass, req| loadedver = Gem::Version.new(eval "#{klass}::VERSION") req.satisfied_by?(loadedver) end end |
.dep_list(name, list, done) ⇒ Object
Compute dependencies recursively build a list in dependency sequence
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/ditto/entity.rb', line 165 def self.dep_list(name, list, done) raise "circular dependency: #{name}" if done.include? name raise "missing dependency: #{name}" unless @@entities.has_key? name deps = @@entities[name].flat_map {|e| e.deps}.uniq done.push name deps.each do |depname| self.dep_list depname, list, done end done.pop list << name unless list.include? name end |
.find_entity_map(name, dataversion, type) ⇒ Object
Given the input data version get the right entity We assume all entity versions with same major work and take the highest
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/ditto/entity.rb', line 138 def self.find_entity_map name, dataversion, type list = @@entities[name].sort{|a,b| b.version <=> a.version} majorversion = dataversion.to_s.slice /^\d+\./ entityreq = Gem::Requirement.new("~>#{majorversion}0") entity = list.find {|e| entityreq.satisfied_by? e.version } raise Error.new(),"#{name}: can't find entity matching dataversion #{dataversion.to_s}" unless entity # Search for the most recent map that matches the database # datamapper objects map = entity.methods.reverse.find do |m| m[0] == type and self.check_dm_versions(m[1]) end raise Error.new(),"#{name}: can't find #{type} map that matches current database" unless map return map end |
.load_entities(filepath, verbose = 0) ⇒ Object
Load entities required by the instances
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/ditto/entity.rb', line 103 def self.load_entities filepath, verbose = 0 puts "loading entities..." if verbose > 0 @@instances.each_key do |name| file = File.("#{name}.ditto", filepath) puts "loading #{file}" if verbose > 1 self.load_from_file File.("#{name}.ditto", filepath) puts "#{name}: #{@@entities[name].inspect}" if verbose > 2 end puts "loaded #{@@entities.size} entities" if verbose > 0 end |
.load_from_file(f) ⇒ Object
Errors discovered in here will be load/syntax errors Stack depth is just empirically determined! TODO WRITE A TEST!
60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/ditto/entity.rb', line 60 def self.load_from_file f begin load File.absolute_path(f) return true rescue Ditto::Error raise rescue SyntaxError => se # Includes the failing location raise Error.new(), "#{se.class}: #{se.to_s}" rescue StandardError => le loc = le.backtrace[0].split(':') raise Error.new(loc), "#{f}: #{le.class}: #{le.to_s}" end end |
.load_instances(f, verbose = 0) ⇒ Object
Load data from YAML files into the in-memory representation return number of instances loaded if all OK
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ditto/entity.rb', line 77 def self.load_instances f, verbose = 0 header = nil version = nil nent = 0 YAML::load_documents(File.open(f)) do |doc| unless header header = Ditto.symbolize_keys doc version = Gem::Version.new(header[:version]) puts (verbose > 1) ? " (version: #{version.to_s})" : "" puts "header #{header.to_s}" if verbose > 2 next end raise Error.new(), "instance has no version header" if version.nil? e = doc.flatten raise Error.new(), "instance malformed" if e.size != 2 name = e[0].to_sym fields = Ditto.symbolize_keys e[1] puts "#{name}: #{fields.inspect}" if verbose > 2 @@instances[name][version] << fields nent += 1 end return nent end |
.reset ⇒ Object
16 17 18 19 |
# File 'lib/ditto/entity.rb', line 16 def self.reset @@entities.clear @@instances.clear end |
.store_all(verbose = 0) ⇒ Object
Store the instances in dependency order
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/ditto/entity.rb', line 116 def self.store_all verbose = 0 seq = [] @@entities.each_key { |name| self.dep_list(name, seq, []) } puts "dependency sequence: #{seq.inspect}" if verbose > 2 nsto = 0 seq.each do |name| @@instances[name].each do |version, instances| map = self.find_entity_map name, version, :add instances.each do |instance| puts "store #{name}: #{instance.inspect}" if verbose > 2 map[2].call OpenStruct.new(instance) nsto += 1 end end end puts "#{nsto} instances stored" if verbose > 0 end |