ditto 0.6.0 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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