Class: Ditto::Entity

Inherits:
Object
  • Object
show all
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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, version, fields, methods) ⇒ Entity

Maps to the ‘entity’ DSL keyword Stack depth is just empirically determined! TODO WRITE A TEST!

Raises:



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
56
# 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}: #{$!.message}")
  @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
  raise Error.new(src), "#{name}: entity missing add method!" unless methods.size > 0

  @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

#depsObject (readonly)

Returns the value of attribute deps.



21
22
23
# File 'lib/ditto/entity.rb', line 21

def deps
  @deps
end

#fieldsObject (readonly)

Returns the value of attribute fields.



21
22
23
# File 'lib/ditto/entity.rb', line 21

def fields
  @fields
end

#locObject (readonly)

Returns the value of attribute loc.



21
22
23
# File 'lib/ditto/entity.rb', line 21

def loc
  @loc
end

#methodsObject (readonly)

Returns the value of attribute methods.



21
22
23
# File 'lib/ditto/entity.rb', line 21

def methods
  @methods
end

#nameObject (readonly)

Returns the value of attribute name.



21
22
23
# File 'lib/ditto/entity.rb', line 21

def name
  @name
end

#versionObject (readonly)

Returns the value of attribute version.



21
22
23
# File 'lib/ditto/entity.rb', line 21

def version
  @version
end

Class Method Details

.dep_list(name, list, done) ⇒ Object

Compute dependencies recursively build a list in dependency sequence



143
144
145
146
147
148
149
150
151
152
153
# File 'lib/ditto/entity.rb', line 143

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(name, version) ⇒ Object

Given the input data version get the right entity



130
131
132
# File 'lib/ditto/entity.rb', line 130

def self.find_entity name, version
   @@entities[name].sort.first
end

.find_map(entity, type) ⇒ Object



134
135
136
137
138
# File 'lib/ditto/entity.rb', line 134

def self.find_map entity, type
  entity.methods.find do |m|
	m[0] == type and true
  end
end

.load_entities(filepath, verbose = 0) ⇒ Object

Load entities required by the instances



102
103
104
105
106
107
108
109
# File 'lib/ditto/entity.rb', line 102

def self.load_entities filepath, verbose = 0
  puts "loading entities..." if verbose > 0
  @@instances.each_key do |name|
	self.load_from_file File.expand_path("#{name}.ditto", filepath)
	puts "#{name}: #{@@entities[name].inspect}" if verbose > 1
  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!



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ditto/entity.rb', line 61

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



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ditto/entity.rb', line 78

def self.load_instances f, verbose = 0
  header = nil
  nent = 0
  YAML::load_documents(File.open(f)) do |doc|
	unless header
	  header = Ditto.symbolize_keys doc
	  puts "header #{header.to_s}" if verbose > 2
	  version = Gem::Version.new(header[:version])
	  puts "version: #{version.to_s}" if verbose > 1
	  next
	end
	e = doc.flatten
	raise Ditto::Error "Entity instance has multiple keys" if e.size != 2
	name = e[0].to_sym
	fields = Ditto.symbolize_keys e[1]
	puts "#{name}: #{fields.inspect}" if verbose > 1
	@@instances[name][version] << fields
	nent += 1
  end
  return nent
end

.resetObject



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



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/ditto/entity.rb', line 113

def self.store_all verbose = 0
  seq = []
  @@entities.each_key { |name| self.dep_list(name, seq, []) }
  puts "dependency sequence: #{seq.inspect}" if verbose > 2
  seq.each do |name|
	@@instances[name].each do |version, instances|
	  entity = self.find_entity name, version
	  map = self.find_map entity, :add
	  instances.each do |instance|
 puts "store #{name}: #{instance.inspect}" if verbose > 2
 map[2].call OpenStruct.new(instance)
	  end
	end
  end
end