ditto 0.6.0 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ditto/dsl.rb +17 -2
- data/lib/ditto/entity.rb +35 -13
- data/lib/ditto/error.rb +1 -1
- data/lib/ditto/runner.rb +8 -5
- data/lib/ditto/version.rb +1 -1
- data/spec/entity_spec.rb +6 -1
- data/spec/fixtures/baddmrequire.ditto +18 -0
- data/test/ditto/currency_group.ditto +16 -1
- metadata +5 -3
data/lib/ditto/dsl.rb
CHANGED
@@ -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
|
data/lib/ditto/entity.rb
CHANGED
@@ -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}"
|
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
|
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 >
|
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 >
|
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
|
-
|
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
|
-
|
131
|
-
|
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.
|
135
|
-
|
136
|
-
|
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
|
|
data/lib/ditto/error.rb
CHANGED
data/lib/ditto/runner.rb
CHANGED
@@ -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
|
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
|
-
|
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 "
|
66
|
-
DataMapper::Logger.new(STDOUT, (@opts.verbose >
|
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
|
data/lib/ditto/version.rb
CHANGED
data/spec/entity_spec.rb
CHANGED
@@ -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
|
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
|
-
#
|
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:
|
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
|