ditto 0.6.0 → 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,13 @@
1
1
  # Define the DSL for Ditto
2
+ # Arguably the validation logic here should be back in entity.rb
2
3
  #
3
4
  module Ditto
4
5
  module DSL
5
6
  def entity (name, version, opts, *methods)
7
+ unless methods.size > 0
8
+ src = Thread.current.backtrace[1].split(':')[0..1]
9
+ raise Error.new(src), "#{name}: entity missing map method!"
10
+ end
6
11
  Ditto::Entity.new(name,version,opts,methods)
7
12
  end
8
13
  def add (version, &block)
@@ -10,14 +15,24 @@ module Ditto
10
15
  src = Thread.current.backtrace[1].split(':')[0..1]
11
16
  raise Error.new(src), "add method missing block (use {} not do/end)"
12
17
  end
13
- [:add, version, block]
18
+ [:add, check_versions(version), block]
14
19
  end
15
20
  def delete (version, &block)
16
21
  unless block
17
22
  src = Thread.current.backtrace[1].split(':')[0..1]
18
23
  raise Error.new(src), "delete method missing block (use {} not do/end)"
19
24
  end
20
- [:delete, version, block]
25
+ [:delete, check_versions(version), block]
26
+ end
27
+ # Check the version hash and convert targets to Gem::Requirements
28
+ #
29
+ def check_versions version
30
+ begin
31
+ version.each {|k,v| version[k] = Gem::Requirement.new(v)}
32
+ rescue
33
+ src = $!.backtrace[9].split(':')[0..1]
34
+ raise Error.new(src), $!.message
35
+ end
21
36
  end
22
37
  end
23
38
  end
@@ -37,7 +37,6 @@ module Ditto
37
37
  raise Error.new(src), "#{name}: previously defined at #{loc.join(':')}"
38
38
  end
39
39
  raise Error.new(src), "#{name}: entity fields must be a hash!" unless fields.kind_of? Hash
40
- raise Error.new(src), "#{name}: entity missing add method!" unless methods.size > 0
41
40
 
42
41
  @fields = Ditto.symbolize_keys fields
43
42
 
@@ -77,20 +76,22 @@ module Ditto
77
76
  #
78
77
  def self.load_instances f, verbose = 0
79
78
  header = nil
79
+ version = nil
80
80
  nent = 0
81
81
  YAML::load_documents(File.open(f)) do |doc|
82
82
  unless header
83
83
  header = Ditto.symbolize_keys doc
84
- puts "header #{header.to_s}" if verbose > 2
85
84
  version = Gem::Version.new(header[:version])
86
- puts "version: #{version.to_s}" if verbose > 1
85
+ puts (verbose > 1) ? " (version: #{version.to_s})" : ""
86
+ puts "header #{header.to_s}" if verbose > 2
87
87
  next
88
88
  end
89
+ raise Error.new(), "instance has no version header" if version.nil?
89
90
  e = doc.flatten
90
- raise Ditto::Error "Entity instance has multiple keys" if e.size != 2
91
+ raise Error.new(), "instance malformed" if e.size != 2
91
92
  name = e[0].to_sym
92
93
  fields = Ditto.symbolize_keys e[1]
93
- puts "#{name}: #{fields.inspect}" if verbose > 1
94
+ puts "#{name}: #{fields.inspect}" if verbose > 2
94
95
  @@instances[name][version] << fields
95
96
  nent += 1
96
97
  end
@@ -102,8 +103,10 @@ module Ditto
102
103
  def self.load_entities filepath, verbose = 0
103
104
  puts "loading entities..." if verbose > 0
104
105
  @@instances.each_key do |name|
106
+ file = File.expand_path("#{name}.ditto", filepath)
107
+ puts "loading #{file}" if verbose > 1
105
108
  self.load_from_file File.expand_path("#{name}.ditto", filepath)
106
- puts "#{name}: #{@@entities[name].inspect}" if verbose > 1
109
+ puts "#{name}: #{@@entities[name].inspect}" if verbose > 2
107
110
  end
108
111
  puts "loaded #{@@entities.size} entities" if verbose > 0
109
112
  end
@@ -114,26 +117,45 @@ module Ditto
114
117
  seq = []
115
118
  @@entities.each_key { |name| self.dep_list(name, seq, []) }
116
119
  puts "dependency sequence: #{seq.inspect}" if verbose > 2
120
+ nsto = 0
117
121
  seq.each do |name|
118
122
  @@instances[name].each do |version, instances|
119
- entity = self.find_entity name, version
120
- map = self.find_map entity, :add
123
+ map = self.find_entity_map name, version, :add
121
124
  instances.each do |instance|
122
125
  puts "store #{name}: #{instance.inspect}" if verbose > 2
123
126
  map[2].call OpenStruct.new(instance)
127
+ nsto += 1
124
128
  end
125
129
  end
126
130
  end
131
+ puts "#{nsto} instances stored" if verbose > 0
127
132
  end
128
133
 
129
134
  # Given the input data version get the right entity
130
- def self.find_entity name, version
131
- @@entities[name].sort.first
135
+ # We assume all entity versions with same major work
136
+ # and take the highest
137
+ #
138
+ def self.find_entity_map name, dataversion, type
139
+ list = @@entities[name].sort{|a,b| b.version <=> a.version}
140
+ majorversion = dataversion.to_s.slice /^\d+\./
141
+ entityreq = Gem::Requirement.new("~>#{majorversion}0")
142
+ entity = list.find {|e| entityreq.satisfied_by? e.version }
143
+ raise Error.new(),"#{name}: can't find entity matching dataversion #{dataversion.to_s}" unless entity
144
+
145
+ # Search for the most recent map that matches the database
146
+ # datamapper objects
147
+
148
+ map = entity.methods.reverse.find do |m|
149
+ m[0] == type and self.check_dm_versions(m[1])
150
+ end
151
+ raise Error.new(),"#{name}: can't find #{type} map that matches current database" unless map
152
+ return map
132
153
  end
133
154
 
134
- def self.find_map entity, type
135
- entity.methods.find do |m|
136
- m[0] == type and true
155
+ def self.check_dm_versions requirements
156
+ requirements.all? do |klass, req|
157
+ loadedver = Gem::Version.new(eval "#{klass}::VERSION")
158
+ req.satisfied_by?(loadedver)
137
159
  end
138
160
  end
139
161
 
@@ -11,7 +11,7 @@ module Ditto
11
11
  end
12
12
  def message debug=false
13
13
  msg = "#{to_s}"
14
- msg += " at #{source(debug)}"
14
+ msg += " at #{source(debug)}" unless src.nil?
15
15
  msg += "\n#{backtrace.join("\n")}" if debug
16
16
  return msg
17
17
  end
@@ -15,15 +15,16 @@ module Ditto
15
15
  load_files @opts.loadfiles
16
16
  exit
17
17
  end
18
+ puts "loading instances..." if @opts.verbose > 0
18
19
  load_files @opts.loadfiles, '.yaml'
19
20
  raise "dittomart file must be specified!" unless @opts.dittomart
20
- puts "dittomart file: #{@opts.dittomart}" if @opts.verbose > 0
21
+ puts "loading dittomart: #{@opts.dittomart}" if @opts.verbose > 0
21
22
  load_files @opts.martfiles, '.dm'
22
23
  Ditto::Entity.load_entities @opts.entitydir, @opts.verbose
23
24
  store_data
24
25
  return 0
25
26
  rescue Ditto::Error => de
26
- STDERR.puts de.message(@opts.debug)
27
+ STDERR.puts "\nError: #{de.message(@opts.debug)}"
27
28
  rescue StandardError => e
28
29
  STDERR.puts "\n#{e.class}: #{e.message}"
29
30
  STDERR.puts e.backtrace if @opts.debug
@@ -39,7 +40,7 @@ module Ditto
39
40
  list.each do |f|
40
41
  ext = File.extname(f)
41
42
  next if type and ext != type
42
- puts "loading #{f}" if @opts.verbose > 0
43
+ print "loading #{f}" if @opts.verbose > 1
43
44
  nfiles += 1
44
45
  case ext
45
46
  when '.yaml'
@@ -47,6 +48,7 @@ module Ditto
47
48
  puts "#{nent} instances loaded" if @opts.verbose > 0
48
49
  when '.ditto'
49
50
  Ditto::Entity.load_from_file f
51
+ puts "" if @opts.verbose > 1
50
52
  when '.dm'
51
53
  begin
52
54
  load File.absolute_path(f)
@@ -54,6 +56,7 @@ module Ditto
54
56
  loc = le.backtrace[2].split(':')
55
57
  puts "Error: #{le.to_s} (line #{loc[1]} in #{loc[0]})"
56
58
  end
59
+ puts "" if @opts.verbose > 1
57
60
  end
58
61
  end
59
62
  puts "#{nfiles} files loaded" if @opts.verbose > 0
@@ -62,8 +65,8 @@ module Ditto
62
65
  # Add the data to the database
63
66
  #
64
67
  def store_data
65
- puts "Running against: #{@opts.connstring}" if @opts.verbose > 0
66
- DataMapper::Logger.new(STDOUT, (@opts.verbose > 1) ? :debug : :info)
68
+ puts "connecting to #{@opts.connstring}" if @opts.verbose > 0
69
+ DataMapper::Logger.new(STDOUT, (@opts.verbose > 2) ? :debug : :info)
67
70
  DataMapper.setup(:default, @opts.connstring)
68
71
  DataMapper.finalize
69
72
  begin
@@ -1,3 +1,3 @@
1
1
  module Ditto
2
- VERSION = '0.6.0'
2
+ VERSION = '1.0'
3
3
  end
@@ -31,13 +31,18 @@ module Ditto
31
31
  it "should identify a comma error" do
32
32
  expect {
33
33
  Ditto::Entity.load_from_file("spec/fixtures/nocomma.ditto")
34
- }.to raise_error Ditto::Error, /missing add/
34
+ }.to raise_error Ditto::Error, /missing map/
35
35
  end
36
36
  it "should identify an invalid mapping" do
37
37
  expect {
38
38
  Ditto::Entity.load_from_file("spec/fixtures/badmap.ditto")
39
39
  }.to raise_error Ditto::Error, /missing block/
40
40
  end
41
+ it "should identify a bad data map requirement" do
42
+ expect {
43
+ Ditto::Entity.load_from_file("spec/fixtures/baddmrequire.ditto")
44
+ }.to raise_error Ditto::Error, /Illformed requirement/
45
+ end
41
46
  it "should parse a method typo" do
42
47
  expect {
43
48
  Ditto::Entity.load_from_file("spec/fixtures/nomethod.ditto")
@@ -0,0 +1,18 @@
1
+ # Ditto entity definitions and mappings for currency_group
2
+ # Bad version requirement on add map
3
+ #
4
+
5
+ entity :currency_group, '1.0.0', {
6
+ :code => [ :mandatory, :unique ],
7
+ :description => nil,
8
+ :is_commodity => nil
9
+ },
10
+ add(CurrencyGroup: '=1=.0.0') { |ditto|
11
+ CurrencyGroup.create(
12
+ :code => ditto.code,
13
+ :description => ditto.description,
14
+ :is_commodity => ditto.is_commodity
15
+ )
16
+ }
17
+
18
+ # vim: set ft=ruby:
@@ -1,4 +1,4 @@
1
- # Ditto entity definitions and mappings for currency_group
1
+ # Correct multiple version entity definition
2
2
  #
3
3
 
4
4
  entity :currency_group, '1.0.0', {
@@ -14,4 +14,19 @@ entity :currency_group, '1.0.0', {
14
14
  )
15
15
  }
16
16
 
17
+ entity :currency_group, '2.0.0', {
18
+ :code => [ :mandatory, :unique ],
19
+ :description => nil,
20
+ :continent => nil,
21
+ :is_commodity => nil
22
+ },
23
+ add(CurrencyGroup: '=2.0.0') { |ditto|
24
+ CurrencyGroup.create(
25
+ :code => ditto.code,
26
+ :description => ditto.description,
27
+ :continent => ditto.continent,
28
+ :is_commodity => ditto.is_commodity
29
+ )
30
+ }
31
+
17
32
  # vim: set ft=ruby:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ditto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: '1.0'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -55,11 +55,11 @@ extensions: []
55
55
  extra_rdoc_files: []
56
56
  files:
57
57
  - lib/ditto/dsl.rb
58
+ - lib/ditto/options.rb
58
59
  - lib/ditto/entity.rb
60
+ - lib/ditto/version.rb
59
61
  - lib/ditto/error.rb
60
- - lib/ditto/options.rb
61
62
  - lib/ditto/runner.rb
62
- - lib/ditto/version.rb
63
63
  - lib/ditto.rb
64
64
  - bin/ditto
65
65
  - features/create_entities.feature
@@ -68,6 +68,7 @@ files:
68
68
  - features/store_entity.feature
69
69
  - features/support/hooks.rb
70
70
  - spec/entity_spec.rb
71
+ - spec/fixtures/baddmrequire.ditto
71
72
  - spec/fixtures/badmap.ditto
72
73
  - spec/fixtures/badver.ditto
73
74
  - spec/fixtures/bigcircle.ditto
@@ -126,6 +127,7 @@ test_files:
126
127
  - features/store_entity.feature
127
128
  - features/support/hooks.rb
128
129
  - spec/entity_spec.rb
130
+ - spec/fixtures/baddmrequire.ditto
129
131
  - spec/fixtures/badmap.ditto
130
132
  - spec/fixtures/badver.ditto
131
133
  - spec/fixtures/bigcircle.ditto