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.
- 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
|