ditto 0.5.0 → 0.6.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/bin/ditto +1 -1
- data/features/create_entities.feature +1 -0
- data/features/load_entity.feature +1 -0
- data/features/store_entity.feature +5 -4
- data/lib/ditto.rb +1 -0
- data/lib/ditto/dsl.rb +14 -9
- data/lib/ditto/entity.rb +118 -106
- data/lib/ditto/error.rb +19 -0
- data/lib/ditto/options.rb +45 -13
- data/lib/ditto/runner.rb +37 -56
- data/lib/ditto/version.rb +1 -1
- data/spec/entity_spec.rb +83 -59
- data/spec/fixtures/badmap.ditto +18 -0
- data/spec/fixtures/badver.ditto +17 -0
- data/spec/fixtures/bigcircle.ditto +17 -0
- data/spec/fixtures/circle.ditto +16 -0
- data/spec/fixtures/continent.ditto +16 -0
- data/spec/fixtures/country.ditto +16 -0
- data/spec/fixtures/currency.ditto +30 -0
- data/spec/fixtures/currency_group.ditto +17 -0
- data/spec/fixtures/dot.ditto +17 -0
- data/spec/fixtures/dupversion.ditto +32 -0
- data/spec/fixtures/good.ditto +17 -0
- data/spec/fixtures/multiversion.ditto +32 -0
- data/spec/fixtures/nocomma.ditto +16 -0
- data/spec/fixtures/nomethod.ditto +18 -0
- data/spec/fixtures/random.ditto +17 -0
- data/spec/fixtures/syntax.ditto +19 -0
- data/spec/options_spec.rb +43 -25
- data/test/data/simple_object.xml +23 -0
- data/test/data/simple_object.yaml +39 -0
- data/test/ditto/currency.ditto +30 -0
- data/test/ditto/currency_group.ditto +17 -0
- data/test/dm/currency-1.0.0.dm +13 -0
- data/test/dm/currency_group-1.0.0.dm +10 -0
- data/test/dm/datamart-1.0 +7 -0
- data/test/dm/nested +2 -0
- data/test/dmtest.rb +41 -0
- data/test/sample.test +2 -0
- metadata +59 -42
- data/lib/ditto/map.rb +0 -39
data/lib/ditto/runner.rb
CHANGED
@@ -1,85 +1,67 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'ditto'
|
3
|
+
require 'data_mapper'
|
3
4
|
|
4
5
|
module Ditto
|
5
6
|
class Runner
|
6
7
|
def initialize(argv)
|
7
|
-
@opts = Options.
|
8
|
-
$: << @opts.modelpath
|
8
|
+
@opts = Options.new(argv)
|
9
9
|
end
|
10
10
|
|
11
11
|
def run
|
12
12
|
begin
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
if @opts.check
|
14
|
+
puts "Checking..." if @opts.verbose > 0
|
15
|
+
load_files @opts.loadfiles
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
load_files @opts.loadfiles, '.yaml'
|
19
|
+
raise "dittomart file must be specified!" unless @opts.dittomart
|
20
|
+
puts "dittomart file: #{@opts.dittomart}" if @opts.verbose > 0
|
21
|
+
load_files @opts.martfiles, '.dm'
|
22
|
+
Ditto::Entity.load_entities @opts.entitydir, @opts.verbose
|
23
|
+
store_data
|
18
24
|
return 0
|
25
|
+
rescue Ditto::Error => de
|
26
|
+
STDERR.puts de.message(@opts.debug)
|
19
27
|
rescue StandardError => e
|
20
|
-
STDERR.puts "\
|
28
|
+
STDERR.puts "\n#{e.class}: #{e.message}"
|
21
29
|
STDERR.puts e.backtrace if @opts.debug
|
22
|
-
return 99
|
23
30
|
end
|
31
|
+
return 99
|
24
32
|
end
|
25
33
|
|
26
|
-
# Load
|
34
|
+
# Load any filetype depending on it's extension
|
27
35
|
#
|
28
|
-
def
|
36
|
+
def load_files list, type = nil
|
29
37
|
nfiles = 0
|
30
38
|
nerr = 0
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
load File.absolute_path(f)
|
36
|
-
nfiles += 1
|
37
|
-
rescue LoadError => le
|
38
|
-
loc = le.backtrace[2].split(':')
|
39
|
-
puts "Error: #{le.to_s} (line #{loc[1]} in #{loc[0]})\nDid you set --modelpath ?"
|
40
|
-
nerr += 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
puts "#{nfiles} definition files loaded" if (nfiles > 0 and @opts.verbose > 0)
|
44
|
-
return nerr == 0
|
45
|
-
end
|
46
|
-
|
47
|
-
# Load data from YAML files into the in-memory representation
|
48
|
-
# return true if all OK
|
49
|
-
#
|
50
|
-
def load_data
|
51
|
-
nfiles = nent = nerr = 0
|
52
|
-
Dir.glob(@opts.loadpaths) do |f|
|
53
|
-
next unless File.extname(f) == '.yaml'
|
39
|
+
list.each do |f|
|
40
|
+
ext = File.extname(f)
|
41
|
+
next if type and ext != type
|
42
|
+
puts "loading #{f}" if @opts.verbose > 0
|
54
43
|
nfiles += 1
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
puts "
|
67
|
-
next
|
44
|
+
case ext
|
45
|
+
when '.yaml'
|
46
|
+
nent = Entity.load_instances f, @opts.verbose
|
47
|
+
puts "#{nent} instances loaded" if @opts.verbose > 0
|
48
|
+
when '.ditto'
|
49
|
+
Ditto::Entity.load_from_file f
|
50
|
+
when '.dm'
|
51
|
+
begin
|
52
|
+
load File.absolute_path(f)
|
53
|
+
rescue ScriptError, StandardError => le
|
54
|
+
loc = le.backtrace[2].split(':')
|
55
|
+
puts "Error: #{le.to_s} (line #{loc[1]} in #{loc[0]})"
|
68
56
|
end
|
69
|
-
Ditto::Entity.load_instance e[0].to_sym, e[1]
|
70
|
-
nent += 1
|
71
57
|
end
|
72
58
|
end
|
73
|
-
puts "#{nfiles}
|
74
|
-
return nerr == 0
|
59
|
+
puts "#{nfiles} files loaded" if @opts.verbose > 0
|
75
60
|
end
|
76
61
|
|
77
62
|
# Add the data to the database
|
78
63
|
#
|
79
64
|
def store_data
|
80
|
-
return true if Ditto::Entity.instance_count == 0
|
81
|
-
return true if Ditto::Entity.entity_count == 0
|
82
|
-
|
83
65
|
puts "Running against: #{@opts.connstring}" if @opts.verbose > 0
|
84
66
|
DataMapper::Logger.new(STDOUT, (@opts.verbose > 1) ? :debug : :info)
|
85
67
|
DataMapper.setup(:default, @opts.connstring)
|
@@ -90,13 +72,12 @@ module Ditto
|
|
90
72
|
else
|
91
73
|
DataMapper.auto_upgrade!
|
92
74
|
end
|
93
|
-
return Ditto::Entity.store_all
|
75
|
+
return Ditto::Entity.store_all @opts.verbose
|
94
76
|
rescue StandardError => e
|
95
77
|
STDERR.puts "\nERROR: #{e.to_s}"
|
96
78
|
STDERR.puts e.backtrace if @opts.debug
|
97
79
|
return false
|
98
80
|
end
|
99
81
|
end
|
100
|
-
|
101
82
|
end
|
102
83
|
end
|
data/lib/ditto/version.rb
CHANGED
data/spec/entity_spec.rb
CHANGED
@@ -2,67 +2,91 @@ require_relative '../lib/ditto/entity'
|
|
2
2
|
|
3
3
|
module Ditto
|
4
4
|
describe Entity do
|
5
|
+
context "When loading a ditto file" do
|
6
|
+
before(:each) do
|
7
|
+
Ditto::Entity.reset
|
8
|
+
end
|
9
|
+
it "should parse correct format" do
|
10
|
+
Ditto::Entity.load_from_file("spec/fixtures/good.ditto").should be_true
|
11
|
+
end
|
12
|
+
it "should parse correct multiple version format" do
|
13
|
+
Ditto::Entity.load_from_file("spec/fixtures/multiversion.ditto").should be_true
|
14
|
+
end
|
15
|
+
it "should not load duplicate multiple version format" do
|
16
|
+
expect {
|
17
|
+
Ditto::Entity.load_from_file("spec/fixtures/dupversion.ditto").should be_true
|
18
|
+
}.to raise_error Ditto::Error, /previously defined/
|
19
|
+
end
|
20
|
+
it "should not load the same one twice" do
|
21
|
+
expect {
|
22
|
+
Ditto::Entity.load_from_file("spec/fixtures/good.ditto").should be_true
|
23
|
+
Ditto::Entity.load_from_file("spec/fixtures/good.ditto").should be_true
|
24
|
+
}.to raise_error Ditto::Error, /previously defined/
|
25
|
+
end
|
26
|
+
it "should parse a syntax error" do
|
27
|
+
expect {
|
28
|
+
Ditto::Entity.load_from_file("spec/fixtures/syntax.ditto")
|
29
|
+
}.to raise_error Ditto::Error, /SyntaxError/
|
30
|
+
end
|
31
|
+
it "should identify a comma error" do
|
32
|
+
expect {
|
33
|
+
Ditto::Entity.load_from_file("spec/fixtures/nocomma.ditto")
|
34
|
+
}.to raise_error Ditto::Error, /missing add/
|
35
|
+
end
|
36
|
+
it "should identify an invalid mapping" do
|
37
|
+
expect {
|
38
|
+
Ditto::Entity.load_from_file("spec/fixtures/badmap.ditto")
|
39
|
+
}.to raise_error Ditto::Error, /missing block/
|
40
|
+
end
|
41
|
+
it "should parse a method typo" do
|
42
|
+
expect {
|
43
|
+
Ditto::Entity.load_from_file("spec/fixtures/nomethod.ditto")
|
44
|
+
}.to raise_error Ditto::Error, /NameError/
|
45
|
+
end
|
46
|
+
it "should identify a bad version" do
|
47
|
+
expect {
|
48
|
+
Ditto::Entity.load_from_file("spec/fixtures/badver.ditto")
|
49
|
+
}.to raise_error Ditto::Error, /Malformed version/
|
50
|
+
end
|
51
|
+
end
|
5
52
|
context "Checking dependencies" do
|
6
53
|
before (:each) do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
expect {
|
44
|
-
Ditto::Entity.dep_list(:bigcircle, [], @deps)
|
45
|
-
}.to raise_error "Missing or circular dependency on bigcircle"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
context "as used in store_all()" do
|
49
|
-
it "should work" do
|
50
|
-
@deps = {
|
51
|
-
:currency_group => [],
|
52
|
-
:currency => [:currency_group],
|
53
|
-
}
|
54
|
-
seq = []
|
55
|
-
Ditto::Entity.dep_list(:currency_group, seq, @deps)
|
56
|
-
Ditto::Entity.dep_list(:currency, seq, @deps)
|
57
|
-
seq.should == [:currency_group, :currency]
|
58
|
-
end
|
59
|
-
it "should work with 3" do
|
60
|
-
seq = []
|
61
|
-
Ditto::Entity.dep_list(:currency_group, seq, @deps)
|
62
|
-
Ditto::Entity.dep_list(:currency, seq, @deps)
|
63
|
-
Ditto::Entity.dep_list(:country, seq, @deps)
|
64
|
-
seq.should == [:currency_group, :currency, :country]
|
65
|
-
end
|
54
|
+
Ditto::Entity.reset
|
55
|
+
Ditto::Entity.load_from_file("spec/fixtures/currency.ditto")
|
56
|
+
Ditto::Entity.load_from_file("spec/fixtures/currency_group.ditto")
|
57
|
+
Ditto::Entity.load_from_file("spec/fixtures/country.ditto")
|
58
|
+
Ditto::Entity.load_from_file("spec/fixtures/continent.ditto")
|
59
|
+
Ditto::Entity.load_from_file("spec/fixtures/random.ditto")
|
60
|
+
Ditto::Entity.load_from_file("spec/fixtures/circle.ditto")
|
61
|
+
Ditto::Entity.load_from_file("spec/fixtures/bigcircle.ditto")
|
62
|
+
Ditto::Entity.load_from_file("spec/fixtures/dot.ditto")
|
63
|
+
end
|
64
|
+
it "should return empty dependency" do
|
65
|
+
Ditto::Entity.dep_list(:currency_group, [], []).should == [:currency_group]
|
66
|
+
end
|
67
|
+
it "should return simple dependency" do
|
68
|
+
Ditto::Entity.dep_list(:currency, [], []).should == [:currency_group, :currency]
|
69
|
+
end
|
70
|
+
it "should return multilevel dependency" do
|
71
|
+
Ditto::Entity.dep_list(:country, [], []).should == [:currency_group, :currency, :country]
|
72
|
+
end
|
73
|
+
it "should return square dependency" do
|
74
|
+
Ditto::Entity.dep_list(:continent, [], []).should == [:currency_group, :currency, :country, :continent]
|
75
|
+
end
|
76
|
+
it "should detect missing dependency" do
|
77
|
+
expect {
|
78
|
+
Ditto::Entity.dep_list(:random, [], [])
|
79
|
+
}.to raise_error "missing dependency: stealth"
|
80
|
+
end
|
81
|
+
it "should detect circular dependency" do
|
82
|
+
expect {
|
83
|
+
Ditto::Entity.dep_list(:circle, [], [])
|
84
|
+
}.to raise_error "circular dependency: circle"
|
85
|
+
end
|
86
|
+
it "should detect bigcircular dependency" do
|
87
|
+
expect {
|
88
|
+
Ditto::Entity.dep_list(:bigcircle, [], [])
|
89
|
+
}.to raise_error "circular dependency: bigcircle"
|
66
90
|
end
|
67
91
|
end
|
68
92
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Ditto entity definitions and mappings for currency_group
|
2
|
+
# Use do/end instead of {} and watch the mapping disappear!
|
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') do |ditto|
|
11
|
+
CurrencyGroup.create(
|
12
|
+
:code => ditto.code,
|
13
|
+
:description => ditto.description,
|
14
|
+
:is_commodity => ditto.is_commodity
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Bad version number
|
2
|
+
#
|
3
|
+
|
4
|
+
entity :currency_group, '1.0.a.', {
|
5
|
+
:code => [ :mandatory, :unique ],
|
6
|
+
:description => nil,
|
7
|
+
:is_commodity => nil
|
8
|
+
},
|
9
|
+
add(CurrencyGroup: '=1.0.0') { |ditto|
|
10
|
+
CurrencyGroup.create(
|
11
|
+
:code => ditto.code,
|
12
|
+
:description => ditto.description,
|
13
|
+
:is_commodity => ditto.is_commodity
|
14
|
+
)
|
15
|
+
}
|
16
|
+
|
17
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Ditto entity definitions and mappings for bigcircle
|
2
|
+
# A simple circular dependency with dot
|
3
|
+
#
|
4
|
+
|
5
|
+
entity :bigcircle, '1.0.0', {
|
6
|
+
code: [ :mandatory, :unique ],
|
7
|
+
description: nil,
|
8
|
+
dot: :related
|
9
|
+
},
|
10
|
+
add(Bigcircle: '~>1.0') { |ditto|
|
11
|
+
Bigcircle.create(
|
12
|
+
:code => ditto.code,
|
13
|
+
:description => ditto.description,
|
14
|
+
:dot => ditto.dot
|
15
|
+
)
|
16
|
+
}
|
17
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Ditto entity definitions and mappings for circular reference
|
2
|
+
#
|
3
|
+
|
4
|
+
entity :circle, '1.0.0', {
|
5
|
+
code: [ :mandatory, :unique ],
|
6
|
+
description: nil,
|
7
|
+
circle: :related
|
8
|
+
},
|
9
|
+
add(Circle: '~>1.0') { |ditto|
|
10
|
+
Circle.create(
|
11
|
+
:code => ditto.code,
|
12
|
+
:description => ditto.description,
|
13
|
+
:circle => ditto.circle
|
14
|
+
)
|
15
|
+
}
|
16
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Ditto entity definitions and mappings for continent
|
2
|
+
#
|
3
|
+
|
4
|
+
entity :continent, '1.0.0', {
|
5
|
+
code: [ :mandatory, :unique ],
|
6
|
+
description: nil,
|
7
|
+
country: :related
|
8
|
+
},
|
9
|
+
add(Continent: '~>1.0') { |ditto|
|
10
|
+
Continent.create(
|
11
|
+
:code => ditto.code,
|
12
|
+
:description => ditto.description,
|
13
|
+
:country => ditto.country
|
14
|
+
)
|
15
|
+
}
|
16
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Ditto entity definitions and mappings for country
|
2
|
+
#
|
3
|
+
|
4
|
+
entity :country, '1.0.0', {
|
5
|
+
code: [ :mandatory, :unique ],
|
6
|
+
description: nil,
|
7
|
+
currency: :related
|
8
|
+
},
|
9
|
+
add(Country: '~>1.0') { |ditto|
|
10
|
+
Country.create(
|
11
|
+
:code => ditto.code,
|
12
|
+
:description => ditto.description,
|
13
|
+
:currency => ditto.currency
|
14
|
+
)
|
15
|
+
}
|
16
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Ditto entity definitions and mappings for currency
|
2
|
+
#
|
3
|
+
|
4
|
+
entity :currency, '1.0.0', {
|
5
|
+
code: [ :mandatory, :unique ],
|
6
|
+
description: nil,
|
7
|
+
exchange_rate: :mandatory,
|
8
|
+
is_designated: nil,
|
9
|
+
currency_group: :related
|
10
|
+
},
|
11
|
+
add(Currency: '~>1.0', CurrencyGroup: '~>1.0') { |ditto|
|
12
|
+
cg = CurrencyGroup.get(ditto.currency_group)
|
13
|
+
cg.currencies.create(
|
14
|
+
:code => ditto.code,
|
15
|
+
:description => ditto.description,
|
16
|
+
:exchange_rate => ditto.exchange_rate,
|
17
|
+
:is_designated => ditto.is_designated
|
18
|
+
)
|
19
|
+
}
|
20
|
+
add(Currency: '~>2.0', CurrencyGroup: '~>2.0') { |ditto|
|
21
|
+
cg = CurrencyGroup.get(ditto.currency_group)
|
22
|
+
cg.currencies.create(
|
23
|
+
:code => ditto.code,
|
24
|
+
:description => ditto.description,
|
25
|
+
:index => 'ghost',
|
26
|
+
:exchange_rate => ditto.exchange_rate,
|
27
|
+
:is_designated => ditto.is_designated
|
28
|
+
)
|
29
|
+
}
|
30
|
+
# vim: set ft=ruby:
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Ditto entity definitions and mappings for currency_group
|
2
|
+
#
|
3
|
+
|
4
|
+
entity :currency_group, '1.0.0', {
|
5
|
+
:code => [ :mandatory, :unique ],
|
6
|
+
:description => nil,
|
7
|
+
:is_commodity => nil
|
8
|
+
},
|
9
|
+
add(CurrencyGroup: '=1.0.0') { |ditto|
|
10
|
+
CurrencyGroup.create(
|
11
|
+
:code => ditto.code,
|
12
|
+
:description => ditto.description,
|
13
|
+
:is_commodity => ditto.is_commodity
|
14
|
+
)
|
15
|
+
}
|
16
|
+
|
17
|
+
# vim: set ft=ruby:
|