abstract_mapper 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -4
- data/CHANGELOG.md +26 -0
- data/README.md +5 -5
- data/Rakefile +1 -1
- data/abstract_mapper.gemspec +1 -0
- data/lib/abstract_mapper.rb +4 -15
- data/lib/abstract_mapper/ast.rb +16 -0
- data/lib/abstract_mapper/ast/branch.rb +121 -0
- data/lib/abstract_mapper/ast/node.rb +91 -0
- data/lib/abstract_mapper/builder.rb +2 -2
- data/lib/abstract_mapper/commands.rb +4 -2
- data/lib/abstract_mapper/commands/base.rb +69 -0
- data/lib/abstract_mapper/dsl.rb +2 -2
- data/lib/abstract_mapper/errors.rb +17 -0
- data/lib/abstract_mapper/errors/wrong_node.rb +1 -1
- data/lib/abstract_mapper/errors/wrong_rule.rb +1 -1
- data/lib/abstract_mapper/optimizer.rb +1 -1
- data/lib/abstract_mapper/rules.rb +10 -5
- data/lib/abstract_mapper/rules/base.rb +74 -0
- data/lib/abstract_mapper/rules/pair.rb +68 -0
- data/lib/abstract_mapper/rules/sole.rb +60 -0
- data/lib/abstract_mapper/settings.rb +22 -30
- data/lib/abstract_mapper/version.rb +1 -1
- data/lib/rspec/nodes.rb +2 -2
- data/spec/integration/faceter.rb +4 -4
- data/spec/integration/rspec_examples_spec.rb +0 -6
- data/spec/unit/abstract_mapper/{branch_spec.rb → ast/branch_spec.rb} +28 -61
- data/spec/unit/abstract_mapper/{node_spec.rb → ast/node_spec.rb} +16 -53
- data/spec/unit/abstract_mapper/builder_spec.rb +9 -24
- data/spec/unit/abstract_mapper/{command_spec.rb → commands/base_spec.rb} +10 -25
- data/spec/unit/abstract_mapper/commands_spec.rb +9 -14
- data/spec/unit/abstract_mapper/dsl_spec.rb +23 -15
- data/spec/unit/abstract_mapper/errors/unknown_command_spec.rb +1 -4
- data/spec/unit/abstract_mapper/errors/wrong_node_spec.rb +5 -4
- data/spec/unit/abstract_mapper/errors/wrong_rule_spec.rb +5 -5
- data/spec/unit/abstract_mapper/functions/compact_spec.rb +0 -2
- data/spec/unit/abstract_mapper/functions/filter_spec.rb +0 -2
- data/spec/unit/abstract_mapper/functions/identity_spec.rb +0 -2
- data/spec/unit/abstract_mapper/functions/restrict_spec.rb +0 -3
- data/spec/unit/abstract_mapper/functions/subclass_spec.rb +0 -2
- data/spec/unit/abstract_mapper/optimizer_spec.rb +13 -17
- data/spec/unit/abstract_mapper/{rule_spec.rb → rules/base_spec.rb} +17 -34
- data/spec/unit/abstract_mapper/{pair_rule_spec.rb → rules/pair_spec.rb} +8 -8
- data/spec/unit/abstract_mapper/{sole_rule_spec.rb → rules/sole_spec.rb} +5 -5
- data/spec/unit/abstract_mapper/rules_spec.rb +24 -37
- data/spec/unit/abstract_mapper/settings_spec.rb +38 -32
- data/spec/unit/abstract_mapper_spec.rb +9 -16
- metadata +37 -22
- data/lib/abstract_mapper/attributes.rb +0 -65
- data/lib/abstract_mapper/branch.rb +0 -120
- data/lib/abstract_mapper/command.rb +0 -68
- data/lib/abstract_mapper/node.rb +0 -87
- data/lib/abstract_mapper/pair_rule.rb +0 -64
- data/lib/abstract_mapper/rule.rb +0 -73
- data/lib/abstract_mapper/sole_rule.rb +0 -56
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class AbstractMapper
|
4
4
|
|
5
|
-
describe AbstractMapper::
|
5
|
+
describe AbstractMapper::Commands::Base do
|
6
6
|
|
7
7
|
let(:command) { described_class.new name, klass, converter }
|
8
8
|
let(:name) { "foo" }
|
@@ -12,55 +12,44 @@ class AbstractMapper
|
|
12
12
|
let(:block) { proc { :foo } }
|
13
13
|
|
14
14
|
describe ".new" do
|
15
|
-
|
16
15
|
subject { command }
|
17
|
-
it { is_expected.to be_frozen }
|
18
16
|
|
17
|
+
it { is_expected.to be_frozen }
|
19
18
|
end # describe .new
|
20
19
|
|
21
20
|
describe "#name" do
|
22
|
-
|
23
21
|
subject { command.name }
|
24
|
-
it { is_expected.to eql name.to_sym }
|
25
22
|
|
23
|
+
it { is_expected.to eql name.to_sym }
|
26
24
|
end # describe #name
|
27
25
|
|
28
26
|
describe "#klass" do
|
29
|
-
|
30
27
|
subject { command.klass }
|
31
|
-
it { is_expected.to eql klass }
|
32
28
|
|
29
|
+
it { is_expected.to eql klass }
|
33
30
|
end # describe #name
|
34
31
|
|
35
32
|
describe "#converter" do
|
36
|
-
|
37
33
|
subject { command.converter }
|
38
34
|
|
39
35
|
context "by default" do
|
40
|
-
|
41
36
|
let(:command) { described_class.new name, klass }
|
42
37
|
|
43
38
|
it "returns identity function" do
|
44
39
|
expect(subject.call(foo: :BAR)).to eql(foo: :BAR)
|
45
40
|
expect(subject.call).to eql({})
|
46
41
|
end
|
47
|
-
|
48
|
-
end # context
|
42
|
+
end
|
49
43
|
|
50
44
|
context "initialized" do
|
51
|
-
|
52
45
|
it { is_expected.to eql converter }
|
53
|
-
|
54
|
-
end # context
|
55
|
-
|
46
|
+
end
|
56
47
|
end # describe #name
|
57
48
|
|
58
49
|
describe "#call" do
|
59
|
-
|
60
50
|
subject { command.call(arguments, &block) }
|
61
51
|
|
62
52
|
context "when the klass is not a branch" do
|
63
|
-
|
64
53
|
it "builds a node" do
|
65
54
|
expect(klass).to receive(:new) do |args, &blk|
|
66
55
|
expect(args).to eql(converter.call(arguments))
|
@@ -68,12 +57,10 @@ class AbstractMapper
|
|
68
57
|
end
|
69
58
|
subject
|
70
59
|
end
|
71
|
-
|
72
|
-
end # context
|
60
|
+
end
|
73
61
|
|
74
62
|
context "when the klass is a branch" do
|
75
|
-
|
76
|
-
let(:klass) { Class.new(Branch) }
|
63
|
+
let(:klass) { Class.new(AST::Branch) }
|
77
64
|
|
78
65
|
it "builds a branch" do
|
79
66
|
expect(klass).to receive(:new) do |args, &blk|
|
@@ -82,11 +69,9 @@ class AbstractMapper
|
|
82
69
|
end
|
83
70
|
subject
|
84
71
|
end
|
85
|
-
|
86
|
-
end # context
|
87
|
-
|
72
|
+
end
|
88
73
|
end # describe #call
|
89
74
|
|
90
|
-
end # describe AbstractMapper::
|
75
|
+
end # describe AbstractMapper::Commands::Base
|
91
76
|
|
92
77
|
end # class AbstractMapper
|
@@ -4,31 +4,29 @@ class AbstractMapper
|
|
4
4
|
|
5
5
|
describe AbstractMapper::Commands do
|
6
6
|
|
7
|
-
let(:foo) { Test::Foo = Class.new(AbstractMapper::Branch) }
|
8
|
-
let(:bar) { Test::Bar = Class.new(AbstractMapper::Node)
|
9
|
-
let(:test) { Class.new(described_class)
|
10
|
-
let(:commands) { test.new
|
11
|
-
let(:converter) { -> v { v.reverse }
|
7
|
+
let(:foo) { Test::Foo = Class.new(AbstractMapper::AST::Branch) }
|
8
|
+
let(:bar) { Test::Bar = Class.new(AbstractMapper::AST::Node) }
|
9
|
+
let(:test) { Class.new(described_class) }
|
10
|
+
let(:commands) { test.new }
|
11
|
+
let(:converter) { -> v { v.reverse } }
|
12
12
|
|
13
13
|
describe ".new" do
|
14
|
+
subject { test.new(registry) }
|
14
15
|
|
15
16
|
let(:registry) { { foo: foo, bar: bar } }
|
16
|
-
subject { test.new(registry) }
|
17
17
|
|
18
18
|
it { is_expected.to be_frozen }
|
19
19
|
|
20
20
|
it "doesn't freeze arguments" do
|
21
21
|
expect { subject }.not_to change { registry.frozen? }
|
22
22
|
end
|
23
|
-
|
24
23
|
end # describe .new
|
25
24
|
|
26
25
|
describe "#[]" do
|
27
|
-
|
28
26
|
subject { commands << ["foo", foo] }
|
29
27
|
|
30
28
|
it "returns registered command" do
|
31
|
-
expect(subject["foo"]).to be_kind_of
|
29
|
+
expect(subject["foo"]).to be_kind_of Commands::Base
|
32
30
|
end
|
33
31
|
|
34
32
|
it "complains about unknown command" do
|
@@ -37,26 +35,23 @@ class AbstractMapper
|
|
37
35
|
expect(error.message).to include "baz"
|
38
36
|
end
|
39
37
|
end
|
40
|
-
|
41
38
|
end # describe #[]
|
42
39
|
|
43
40
|
describe "#<<" do
|
44
|
-
|
45
41
|
subject { commands << ["foo", foo] << ["bar", bar, converter] }
|
46
42
|
|
47
43
|
it { is_expected.to be_kind_of test }
|
48
44
|
|
49
45
|
it "preserves registered commands" do
|
50
|
-
expect(subject[:foo]).to be_kind_of
|
46
|
+
expect(subject[:foo]).to be_kind_of Commands::Base
|
51
47
|
end
|
52
48
|
|
53
49
|
it "registers new command" do
|
54
|
-
expect(subject[:bar]).to be_kind_of
|
50
|
+
expect(subject[:bar]).to be_kind_of Commands::Base
|
55
51
|
expect(subject[:bar].name).to eql :bar
|
56
52
|
expect(subject[:bar].klass).to eql bar
|
57
53
|
expect(subject[:bar].converter).to eql converter
|
58
54
|
end
|
59
|
-
|
60
55
|
end # describe #<<
|
61
56
|
|
62
57
|
end # describe AbstractMapper::Commands
|
@@ -5,11 +5,10 @@ class AbstractMapper
|
|
5
5
|
describe AbstractMapper::DSL do
|
6
6
|
|
7
7
|
let!(:dsl) { Class.new { extend DSL } }
|
8
|
-
let!(:foo) { Test::Foo = Class.new(Node) { attribute :foo } }
|
9
|
-
let!(:bar) { Test::Bar = Class.new(Branch) { attribute :bar } }
|
10
|
-
|
8
|
+
let!(:foo) { Test::Foo = Class.new(AST::Node) { attribute :foo } }
|
9
|
+
let!(:bar) { Test::Bar = Class.new(AST::Branch) { attribute :bar } }
|
11
10
|
let!(:rule) do
|
12
|
-
Test::Rule = Class.new(
|
11
|
+
Test::Rule = Class.new(Rules::Pair) do
|
13
12
|
def optimize?
|
14
13
|
left.instance_of?(Test::Foo)
|
15
14
|
end
|
@@ -19,7 +18,6 @@ class AbstractMapper
|
|
19
18
|
end
|
20
19
|
end
|
21
20
|
end
|
22
|
-
|
23
21
|
let!(:config) do
|
24
22
|
dsl.configure do
|
25
23
|
command :foo, Test::Foo
|
@@ -29,21 +27,36 @@ class AbstractMapper
|
|
29
27
|
end
|
30
28
|
|
31
29
|
describe "#configure" do
|
32
|
-
|
33
30
|
subject { config }
|
34
31
|
|
35
|
-
it
|
32
|
+
it "returns self" do
|
33
|
+
expect(subject).to eql dsl
|
34
|
+
end
|
36
35
|
|
37
36
|
it "configures settings" do
|
38
37
|
subject
|
38
|
+
|
39
39
|
expect(dsl.settings).to be_kind_of Settings
|
40
40
|
expect(dsl.settings.rules.registry).to eql [rule]
|
41
41
|
expect { dsl.settings.commands[:foo] }.not_to raise_error
|
42
42
|
end
|
43
43
|
|
44
|
+
it "updates existing settings" do
|
45
|
+
subject
|
46
|
+
dsl.configure do
|
47
|
+
command :baz, Test::Foo
|
48
|
+
end
|
49
|
+
|
50
|
+
expect(dsl.settings).to be_kind_of Settings
|
51
|
+
expect(dsl.settings.rules.registry).to eql [rule]
|
52
|
+
expect { dsl.settings.commands[:foo] }.not_to raise_error
|
53
|
+
expect { dsl.settings.commands[:bar] }.not_to raise_error
|
54
|
+
expect { dsl.settings.commands[:baz] }.not_to raise_error
|
55
|
+
end
|
44
56
|
end # describe #configure
|
45
57
|
|
46
58
|
describe "#finalize" do
|
59
|
+
subject { dsl.finalize }
|
47
60
|
|
48
61
|
before do
|
49
62
|
dsl.instance_eval do
|
@@ -55,31 +68,26 @@ class AbstractMapper
|
|
55
68
|
end
|
56
69
|
end
|
57
70
|
|
58
|
-
|
59
|
-
|
60
|
-
it { is_expected.to be_kind_of Branch }
|
71
|
+
it { is_expected.to be_kind_of AST::Branch }
|
61
72
|
|
62
73
|
it "is optimized" do
|
63
74
|
desc = "<Root [<Bar(bar: :baz) [<Foo(foo: :quxx)>]>, <Foo(foo: :foo)>]>"
|
64
75
|
expect(subject.inspect).to eql(desc)
|
65
76
|
end
|
66
|
-
|
67
77
|
end # describe #finalize
|
68
78
|
|
69
79
|
describe "#respond_to?" do
|
70
|
-
|
71
80
|
subject { dsl.respond_to? :anything }
|
72
|
-
it { is_expected.to eql true }
|
73
81
|
|
82
|
+
it { is_expected.to eql true }
|
74
83
|
end # describe #respond_to?
|
75
84
|
|
76
85
|
describe ".inherited" do
|
86
|
+
subject { subklass.settings }
|
77
87
|
|
78
88
|
let(:subklass) { Class.new(dsl) }
|
79
|
-
subject { subklass.settings }
|
80
89
|
|
81
90
|
it { is_expected.to eql dsl.settings }
|
82
|
-
|
83
91
|
end # describe .inherited
|
84
92
|
|
85
93
|
end # describe AbstractMapper::DSL
|
@@ -5,17 +5,14 @@ describe AbstractMapper::Errors::UnknownCommand do
|
|
5
5
|
subject(:error) { described_class.new :foo }
|
6
6
|
|
7
7
|
describe ".new" do
|
8
|
-
|
9
8
|
it { is_expected.to be_kind_of NameError }
|
10
9
|
it { is_expected.to be_frozen }
|
11
|
-
|
12
10
|
end # describe .new
|
13
11
|
|
14
12
|
describe "#message" do
|
15
|
-
|
16
13
|
subject { error.message }
|
17
|
-
it { is_expected.to eql "'foo' is not a registered DSL command" }
|
18
14
|
|
15
|
+
it { is_expected.to eql "'foo' is not a registered DSL command" }
|
19
16
|
end # describe #message
|
20
17
|
|
21
18
|
end # describe AbstractMapper::Errors::UnknownCommand
|
@@ -2,20 +2,21 @@
|
|
2
2
|
|
3
3
|
describe AbstractMapper::Errors::WrongNode do
|
4
4
|
|
5
|
-
|
5
|
+
let(:error) { described_class.new Symbol }
|
6
6
|
|
7
7
|
describe ".new" do
|
8
|
+
subject { error }
|
8
9
|
|
9
10
|
it { is_expected.to be_kind_of TypeError }
|
10
11
|
it { is_expected.to be_frozen }
|
11
|
-
|
12
12
|
end # describe .new
|
13
13
|
|
14
14
|
describe "#message" do
|
15
|
-
|
16
15
|
subject { error.message }
|
17
|
-
it { is_expected.to eql "Symbol is not a subclass of AbstractMapper::Node" }
|
18
16
|
|
17
|
+
it do
|
18
|
+
is_expected.to eql "Symbol is not a subclass of AbstractMapper::AST::Node"
|
19
|
+
end
|
19
20
|
end # describe #message
|
20
21
|
|
21
22
|
end # describe AbstractMapper::Errors::WrongNode
|
@@ -2,22 +2,22 @@
|
|
2
2
|
|
3
3
|
describe AbstractMapper::Errors::WrongRule do
|
4
4
|
|
5
|
-
|
5
|
+
let(:error) { described_class.new Symbol }
|
6
6
|
|
7
7
|
describe ".new" do
|
8
|
+
subject { error }
|
8
9
|
|
9
10
|
it { is_expected.to be_kind_of TypeError }
|
10
11
|
it { is_expected.to be_frozen }
|
11
|
-
|
12
12
|
end # describe .new
|
13
13
|
|
14
14
|
describe "#message" do
|
15
|
-
|
16
15
|
subject { error.message }
|
16
|
+
|
17
17
|
it do
|
18
|
-
is_expected
|
18
|
+
is_expected
|
19
|
+
.to eql "Symbol is not a subclass of AbstractMapper::Rules::Base"
|
19
20
|
end
|
20
|
-
|
21
21
|
end # describe #message
|
22
22
|
|
23
23
|
end # describe AbstractMapper::Errors::WrongRule
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "transproc/rspec"
|
4
4
|
|
5
5
|
describe AbstractMapper::Functions, "#compact" do
|
6
|
-
|
7
6
|
let(:fn) { -> a, b { (a == b) ? [a + b] : [a, b] } }
|
8
7
|
let(:arguments) { [:compact, fn] }
|
9
8
|
|
@@ -21,5 +20,4 @@ describe AbstractMapper::Functions, "#compact" do
|
|
21
20
|
let(:input) { [1, 1, 2, 3, 3] }
|
22
21
|
let(:output) { [4, 6] }
|
23
22
|
end
|
24
|
-
|
25
23
|
end # describe AbstractMapper::Functions#compact
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "transproc/rspec"
|
4
4
|
|
5
5
|
describe AbstractMapper::Functions, "#filter" do
|
6
|
-
|
7
6
|
let(:arguments) { [:filter, -> v { v - 1 if v > 3 }] }
|
8
7
|
|
9
8
|
it_behaves_like :transforming_immutable_data do
|
@@ -22,5 +21,4 @@ describe AbstractMapper::Functions, "#filter" do
|
|
22
21
|
let(:input) { [1, 4, 9, 7, 2, 5] }
|
23
22
|
let(:output) { [3, 8, 6, 4] }
|
24
23
|
end
|
25
|
-
|
26
24
|
end # describe AbstractMapper::Functions#filter
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "transproc/rspec"
|
4
4
|
|
5
5
|
describe AbstractMapper::Functions, "#identity" do
|
6
|
-
|
7
6
|
it_behaves_like :transforming_immutable_data do
|
8
7
|
let(:arguments) { [:identity] }
|
9
8
|
|
@@ -17,5 +16,4 @@ describe AbstractMapper::Functions, "#identity" do
|
|
17
16
|
let(:input) { :foo }
|
18
17
|
let(:output) { :foo }
|
19
18
|
end
|
20
|
-
|
21
19
|
end # describe AbstractMapper::Functions#identity
|
@@ -3,14 +3,11 @@
|
|
3
3
|
require "transproc/rspec"
|
4
4
|
|
5
5
|
describe AbstractMapper::Functions, "#restrict" do
|
6
|
-
|
7
6
|
let(:arguments) { [:restrict, default] }
|
8
7
|
let(:default) { { foo: :FOO, bar: :BAR } }
|
9
8
|
|
10
9
|
it_behaves_like :transforming_immutable_data do
|
11
|
-
|
12
10
|
let(:input) { { foo: :BAZ, qux: :QUX } }
|
13
11
|
let(:output) { { foo: :BAZ, bar: :BAR } }
|
14
12
|
end
|
15
|
-
|
16
13
|
end # describe AbstractMapper::Functions#restrict
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "transproc/rspec"
|
4
4
|
|
5
5
|
describe AbstractMapper::Functions, "#subclass?" do
|
6
|
-
|
7
6
|
let(:klass) { Class.new }
|
8
7
|
let(:modul) { Module.new }
|
9
8
|
|
@@ -62,5 +61,4 @@ describe AbstractMapper::Functions, "#subclass?" do
|
|
62
61
|
let(:input) { Module.new.send :extend, modul }
|
63
62
|
let(:output) { false }
|
64
63
|
end
|
65
|
-
|
66
64
|
end # describe AbstractMapper::Functions#subclass?
|
@@ -9,44 +9,40 @@ class AbstractMapper # namespace
|
|
9
9
|
let(:rules) { Rules.new }
|
10
10
|
|
11
11
|
describe ".new" do
|
12
|
-
|
13
12
|
subject { optimizer }
|
14
|
-
it { is_expected.to be_frozen }
|
15
13
|
|
14
|
+
it { is_expected.to be_frozen }
|
16
15
|
end # describe .new
|
17
16
|
|
18
17
|
describe "#rules" do
|
19
|
-
|
20
18
|
subject { optimizer.rules }
|
21
|
-
it { is_expected.to eql rules }
|
22
19
|
|
20
|
+
it { is_expected.to eql rules }
|
23
21
|
end # describe #rules
|
24
22
|
|
25
23
|
describe "#update" do
|
24
|
+
subject { optimizer.update(input) }
|
26
25
|
|
27
|
-
|
26
|
+
let(:rules) { Rules.new([rule]) }
|
27
|
+
let(:rule) { Class.new(Rules::Pair) }
|
28
|
+
let(:input) { AST::Branch.new { [foo3, bar1] } }
|
28
29
|
|
29
|
-
let(:
|
30
|
-
let(:
|
31
|
-
let(:
|
32
|
-
|
33
|
-
let(:foo1) { Test::Foo.new(n: 1) }
|
34
|
-
let(:foo2) { Test::Foo.new(n: 2) }
|
35
|
-
let(:foo3) { Test::Foo.new(n: 3) }
|
30
|
+
let(:foo1) { Test::Foo.new(n: 1) }
|
31
|
+
let(:foo2) { Test::Foo.new(n: 2) }
|
32
|
+
let(:foo3) { Test::Foo.new(n: 3) }
|
36
33
|
let(:bar1) { Test::Bar.new(n: 4) { [foo1, foo2] } }
|
37
34
|
|
38
|
-
before { Test::Foo = Class.new(Node) { attribute :n }
|
39
|
-
before { Test::Bar = Class.new(Branch)
|
40
|
-
before { rule.send(:define_method, :optimize?) { true }
|
35
|
+
before { Test::Foo = Class.new(AST::Node) { attribute :n } }
|
36
|
+
before { Test::Bar = Class.new(AST::Branch) }
|
37
|
+
before { rule.send(:define_method, :optimize?) { true } }
|
41
38
|
before { rule.send(:define_method, :optimize) { nodes.reverse } }
|
42
39
|
|
43
40
|
it "optimizes the tree deeply" do
|
44
|
-
expect(
|
41
|
+
expect(input.inspect)
|
45
42
|
.to eql "<Root [<Foo(n: 3)>, <Bar [<Foo(n: 1)>, <Foo(n: 2)>]>]>"
|
46
43
|
expect(subject.inspect)
|
47
44
|
.to eql "<Root [<Bar [<Foo(n: 2)>, <Foo(n: 1)>]>, <Foo(n: 3)>]>"
|
48
45
|
end
|
49
|
-
|
50
46
|
end # describe #update
|
51
47
|
|
52
48
|
end # describe AbstractMapper::Optimize
|