abstract_mapper 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +34 -0
- data/Gemfile +1 -3
- data/README.md +29 -13
- data/Rakefile +4 -7
- data/abstract_mapper.gemspec +3 -2
- data/config/metrics/STYLEGUIDE +14 -15
- data/lib/abstract_mapper.rb +4 -1
- data/lib/abstract_mapper/attributes.rb +65 -0
- data/lib/abstract_mapper/branch.rb +17 -7
- data/lib/abstract_mapper/builder.rb +7 -3
- data/lib/abstract_mapper/command.rb +68 -0
- data/lib/abstract_mapper/commands.rb +11 -31
- data/lib/abstract_mapper/errors/unknown_command.rb +1 -1
- data/lib/abstract_mapper/errors/wrong_node.rb +1 -1
- data/lib/abstract_mapper/errors/wrong_rule.rb +2 -2
- data/lib/abstract_mapper/functions.rb +32 -5
- data/lib/abstract_mapper/node.rb +21 -10
- data/lib/abstract_mapper/optimizer.rb +3 -3
- data/lib/abstract_mapper/pair_rule.rb +2 -4
- data/lib/abstract_mapper/rspec.rb +1 -2
- data/lib/abstract_mapper/rule.rb +23 -2
- data/lib/abstract_mapper/rules.rb +3 -10
- data/lib/abstract_mapper/settings.rb +3 -3
- data/lib/abstract_mapper/sole_rule.rb +2 -4
- data/lib/abstract_mapper/version.rb +1 -1
- data/lib/rspec/doubles.rb +16 -0
- data/lib/rspec/nodes.rb +29 -16
- data/lib/rspec/rules.rb +3 -3
- data/spec/integration/faceter.rb +16 -7
- data/spec/integration/mapper_definition_spec.rb +1 -1
- data/spec/integration/rspec_examples_spec.rb +4 -30
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/abstract_mapper/branch_spec.rb +91 -14
- data/spec/unit/abstract_mapper/builder_spec.rb +66 -48
- data/spec/unit/abstract_mapper/command_spec.rb +92 -0
- data/spec/unit/abstract_mapper/commands_spec.rb +38 -79
- data/spec/unit/abstract_mapper/dsl_spec.rb +60 -55
- data/spec/unit/abstract_mapper/errors/wrong_rule_spec.rb +1 -1
- data/spec/unit/abstract_mapper/functions/compact_spec.rb +3 -3
- data/spec/unit/abstract_mapper/functions/filter_spec.rb +1 -1
- data/spec/unit/abstract_mapper/functions/identity_spec.rb +21 -0
- data/spec/unit/abstract_mapper/functions/restrict_spec.rb +16 -0
- data/spec/unit/abstract_mapper/functions/subclass_spec.rb +1 -1
- data/spec/unit/abstract_mapper/node_spec.rb +119 -48
- data/spec/unit/abstract_mapper/optimizer_spec.rb +38 -32
- data/spec/unit/abstract_mapper/pair_rule_spec.rb +4 -11
- data/spec/unit/abstract_mapper/rule_spec.rb +31 -15
- data/spec/unit/abstract_mapper/rules_spec.rb +2 -2
- data/spec/unit/abstract_mapper/settings_spec.rb +80 -73
- data/spec/unit/abstract_mapper/sole_rule_spec.rb +3 -10
- data/spec/unit/abstract_mapper_spec.rb +13 -5
- metadata +33 -12
- data/lib/rspec/functions.rb +0 -25
- data/lib/rspec/mapper.rb +0 -40
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class AbstractMapper
|
4
|
+
|
5
|
+
describe AbstractMapper::Command do
|
6
|
+
|
7
|
+
let(:command) { described_class.new name, klass, converter }
|
8
|
+
let(:name) { "foo" }
|
9
|
+
let(:klass) { Class.new }
|
10
|
+
let(:converter) { -> *args { args.reverse } }
|
11
|
+
let(:arguments) { [baz: :QUX] }
|
12
|
+
let(:block) { proc { :foo } }
|
13
|
+
|
14
|
+
describe ".new" do
|
15
|
+
|
16
|
+
subject { command }
|
17
|
+
it { is_expected.to be_frozen }
|
18
|
+
|
19
|
+
end # describe .new
|
20
|
+
|
21
|
+
describe "#name" do
|
22
|
+
|
23
|
+
subject { command.name }
|
24
|
+
it { is_expected.to eql name.to_sym }
|
25
|
+
|
26
|
+
end # describe #name
|
27
|
+
|
28
|
+
describe "#klass" do
|
29
|
+
|
30
|
+
subject { command.klass }
|
31
|
+
it { is_expected.to eql klass }
|
32
|
+
|
33
|
+
end # describe #name
|
34
|
+
|
35
|
+
describe "#converter" do
|
36
|
+
|
37
|
+
subject { command.converter }
|
38
|
+
|
39
|
+
context "by default" do
|
40
|
+
|
41
|
+
let(:command) { described_class.new name, klass }
|
42
|
+
|
43
|
+
it "returns identity function" do
|
44
|
+
expect(subject.call(foo: :BAR)).to eql(foo: :BAR)
|
45
|
+
expect(subject.call).to eql({})
|
46
|
+
end
|
47
|
+
|
48
|
+
end # context
|
49
|
+
|
50
|
+
context "initialized" do
|
51
|
+
|
52
|
+
it { is_expected.to eql converter }
|
53
|
+
|
54
|
+
end # context
|
55
|
+
|
56
|
+
end # describe #name
|
57
|
+
|
58
|
+
describe "#call" do
|
59
|
+
|
60
|
+
subject { command.call(arguments, &block) }
|
61
|
+
|
62
|
+
context "when the klass is not a branch" do
|
63
|
+
|
64
|
+
it "builds a node" do
|
65
|
+
expect(klass).to receive(:new) do |args, &blk|
|
66
|
+
expect(args).to eql(converter.call(arguments))
|
67
|
+
expect(blk).to eql block
|
68
|
+
end
|
69
|
+
subject
|
70
|
+
end
|
71
|
+
|
72
|
+
end # context
|
73
|
+
|
74
|
+
context "when the klass is a branch" do
|
75
|
+
|
76
|
+
let(:klass) { Class.new(Branch) }
|
77
|
+
|
78
|
+
it "builds a branch" do
|
79
|
+
expect(klass).to receive(:new) do |args, &blk|
|
80
|
+
expect(args).to eql(converter.call(arguments))
|
81
|
+
expect(blk).to be_nil
|
82
|
+
end
|
83
|
+
subject
|
84
|
+
end
|
85
|
+
|
86
|
+
end # context
|
87
|
+
|
88
|
+
end # describe #call
|
89
|
+
|
90
|
+
end # describe AbstractMapper::Command
|
91
|
+
|
92
|
+
end # class AbstractMapper
|
@@ -1,105 +1,64 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
3
|
+
class AbstractMapper
|
4
4
|
|
5
|
-
|
6
|
-
let(:test) { Class.new(described_class) }
|
7
|
-
let(:branch) { Class.new(AbstractMapper::Branch) }
|
5
|
+
describe AbstractMapper::Commands do
|
8
6
|
|
9
|
-
|
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 } }
|
10
12
|
|
11
|
-
|
12
|
-
it { is_expected.to be_frozen }
|
13
|
+
describe ".new" do
|
13
14
|
|
14
|
-
|
15
|
+
let(:registry) { { foo: foo, bar: bar } }
|
16
|
+
subject { test.new(registry) }
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
subject { commands.registry }
|
19
|
-
|
20
|
-
context "with a hash" do
|
21
|
-
|
22
|
-
let(:commands) { test.new(registry) }
|
23
|
-
let(:registry) { { foo: branch } }
|
24
|
-
|
25
|
-
it { is_expected.to eql registry }
|
26
|
-
it { is_expected.to be_frozen }
|
18
|
+
it { is_expected.to be_frozen }
|
27
19
|
|
28
|
-
it "doesn't freeze
|
20
|
+
it "doesn't freeze arguments" do
|
29
21
|
expect { subject }.not_to change { registry.frozen? }
|
30
22
|
end
|
31
23
|
|
32
|
-
end #
|
33
|
-
|
34
|
-
context "without a hash" do
|
35
|
-
|
36
|
-
let(:commands) { test.new }
|
37
|
-
|
38
|
-
it { is_expected.to eql({}) }
|
39
|
-
it { is_expected.to be_frozen }
|
40
|
-
|
41
|
-
end # context
|
42
|
-
|
43
|
-
end # describe #builder
|
44
|
-
|
45
|
-
describe "#<<" do
|
46
|
-
|
47
|
-
let(:commands) { test.new(foo: branch) }
|
48
|
-
|
49
|
-
subject { commands << ["bar", branch] }
|
24
|
+
end # describe .new
|
50
25
|
|
51
|
-
|
52
|
-
expect(subject).to be_kind_of test
|
53
|
-
expect(subject.registry).to eql(foo: branch, bar: branch)
|
54
|
-
end
|
26
|
+
describe "#[]" do
|
55
27
|
|
56
|
-
|
28
|
+
subject { commands << ["foo", foo] }
|
57
29
|
|
58
|
-
|
59
|
-
|
60
|
-
let(:block) { proc { [:foo] } }
|
61
|
-
let(:args) { [:baz, qux: :QUX] }
|
62
|
-
let(:commands) do
|
63
|
-
test.new(foo: AbstractMapper::Node, bar: AbstractMapper::Branch)
|
64
|
-
end
|
65
|
-
|
66
|
-
context "simple node" do
|
67
|
-
|
68
|
-
subject { commands["foo", *args, &block] }
|
69
|
-
|
70
|
-
it "builds a node with a block" do
|
71
|
-
expect(subject).to be_kind_of AbstractMapper::Node
|
72
|
-
expect(subject.attributes).to eql args
|
73
|
-
expect(subject.block).to eql block
|
30
|
+
it "returns registered command" do
|
31
|
+
expect(subject["foo"]).to be_kind_of Command
|
74
32
|
end
|
75
33
|
|
76
|
-
|
77
|
-
|
78
|
-
|
34
|
+
it "complains about unknown command" do
|
35
|
+
expect { subject[:baz] }.to raise_error do |error|
|
36
|
+
expect(error).to be_kind_of AbstractMapper::Errors::UnknownCommand
|
37
|
+
expect(error.message).to include "baz"
|
38
|
+
end
|
39
|
+
end
|
79
40
|
|
80
|
-
|
41
|
+
end # describe #[]
|
81
42
|
|
82
|
-
|
83
|
-
expect(subject).to be_kind_of AbstractMapper::Node
|
84
|
-
expect(subject.attributes).to eql args
|
85
|
-
expect(subject.entries).to eql []
|
86
|
-
end
|
43
|
+
describe "#<<" do
|
87
44
|
|
88
|
-
|
45
|
+
subject { commands << ["foo", foo] << ["bar", bar, converter] }
|
89
46
|
|
90
|
-
|
47
|
+
it { is_expected.to be_kind_of test }
|
91
48
|
|
92
|
-
|
49
|
+
it "preserves registered commands" do
|
50
|
+
expect(subject[:foo]).to be_kind_of Command
|
51
|
+
end
|
93
52
|
|
94
|
-
it "
|
95
|
-
expect
|
96
|
-
|
97
|
-
|
98
|
-
|
53
|
+
it "registers new command" do
|
54
|
+
expect(subject[:bar]).to be_kind_of Command
|
55
|
+
expect(subject[:bar].name).to eql :bar
|
56
|
+
expect(subject[:bar].klass).to eql bar
|
57
|
+
expect(subject[:bar].converter).to eql converter
|
99
58
|
end
|
100
59
|
|
101
|
-
end #
|
60
|
+
end # describe #<<
|
102
61
|
|
103
|
-
end # describe
|
62
|
+
end # describe AbstractMapper::Commands
|
104
63
|
|
105
|
-
end #
|
64
|
+
end # class AbstractMapper
|
@@ -1,82 +1,87 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
let!(:foo) { AbstractMapper::Test::Foo = Class.new(AbstractMapper::Node) }
|
7
|
-
let!(:rule) do
|
8
|
-
AbstractMapper::Test::Rule = Class.new(AbstractMapper::PairRule) do
|
9
|
-
def optimize?
|
10
|
-
left.instance_of?(AbstractMapper::Test::Foo)
|
11
|
-
end
|
3
|
+
class AbstractMapper
|
4
|
+
|
5
|
+
describe AbstractMapper::DSL do
|
12
6
|
|
13
|
-
|
14
|
-
|
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
|
+
|
11
|
+
let!(:rule) do
|
12
|
+
Test::Rule = Class.new(PairRule) do
|
13
|
+
def optimize?
|
14
|
+
left.instance_of?(Test::Foo)
|
15
|
+
end
|
16
|
+
|
17
|
+
def optimize
|
18
|
+
Test::Foo.new(left.attributes.merge(right.attributes))
|
19
|
+
end
|
15
20
|
end
|
16
21
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
rule AbstractMapper::Test::Rule
|
22
|
+
|
23
|
+
let!(:config) do
|
24
|
+
dsl.configure do
|
25
|
+
command :foo, Test::Foo
|
26
|
+
command(:bar, Test::Bar) { |value| { bar: value } }
|
27
|
+
rule Test::Rule
|
28
|
+
end
|
25
29
|
end
|
26
|
-
end
|
27
30
|
|
28
|
-
|
31
|
+
describe "#configure" do
|
29
32
|
|
30
|
-
|
33
|
+
subject { config }
|
31
34
|
|
32
|
-
|
35
|
+
it { is_expected.to eql dsl }
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
it "configures settings" do
|
38
|
+
subject
|
39
|
+
expect(dsl.settings).to be_kind_of Settings
|
40
|
+
expect(dsl.settings.rules.registry).to eql [rule]
|
41
|
+
expect { dsl.settings.commands[:foo] }.not_to raise_error
|
42
|
+
end
|
40
43
|
|
41
|
-
|
44
|
+
end # describe #configure
|
42
45
|
|
43
|
-
|
46
|
+
describe "#finalize" do
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
before do
|
49
|
+
dsl.instance_eval do
|
50
|
+
bar :baz do
|
51
|
+
foo foo: :qux
|
52
|
+
foo foo: :quxx
|
53
|
+
end
|
54
|
+
foo foo: :foo
|
50
55
|
end
|
51
|
-
foo :foo
|
52
56
|
end
|
53
|
-
end
|
54
57
|
|
55
|
-
|
58
|
+
subject { dsl.finalize }
|
56
59
|
|
57
|
-
|
60
|
+
it { is_expected.to be_kind_of Branch }
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
.to eql
|
62
|
-
|
62
|
+
it "is optimized" do
|
63
|
+
desc = "<Root [<Bar(bar: :baz) [<Foo(foo: :quxx)>]>, <Foo(foo: :foo)>]>"
|
64
|
+
expect(subject.inspect).to eql(desc)
|
65
|
+
end
|
66
|
+
|
67
|
+
end # describe #finalize
|
63
68
|
|
64
|
-
|
69
|
+
describe "#respond_to?" do
|
65
70
|
|
66
|
-
|
71
|
+
subject { dsl.respond_to? :anything }
|
72
|
+
it { is_expected.to eql true }
|
67
73
|
|
68
|
-
|
69
|
-
it { is_expected.to eql true }
|
74
|
+
end # describe #respond_to?
|
70
75
|
|
71
|
-
|
76
|
+
describe ".inherited" do
|
72
77
|
|
73
|
-
|
78
|
+
let(:subklass) { Class.new(dsl) }
|
79
|
+
subject { subklass.settings }
|
74
80
|
|
75
|
-
|
76
|
-
subject { subklass.settings }
|
81
|
+
it { is_expected.to eql dsl.settings }
|
77
82
|
|
78
|
-
|
83
|
+
end # describe .inherited
|
79
84
|
|
80
|
-
end # describe
|
85
|
+
end # describe AbstractMapper::DSL
|
81
86
|
|
82
|
-
end #
|
87
|
+
end # class AbstractMapper
|
@@ -15,7 +15,7 @@ describe AbstractMapper::Errors::WrongRule do
|
|
15
15
|
|
16
16
|
subject { error.message }
|
17
17
|
it do
|
18
|
-
is_expected.to eql "Symbol is not a subclass of AbstractMapper::
|
18
|
+
is_expected.to eql "Symbol is not a subclass of AbstractMapper::Rule"
|
19
19
|
end
|
20
20
|
|
21
21
|
end # describe #message
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "transproc/rspec"
|
4
4
|
|
5
5
|
describe AbstractMapper::Functions, "#compact" do
|
6
6
|
|
7
|
-
let(:
|
8
|
-
let(:arguments) { [:compact,
|
7
|
+
let(:fn) { -> a, b { (a == b) ? [a + b] : [a, b] } }
|
8
|
+
let(:arguments) { [:compact, fn] }
|
9
9
|
|
10
10
|
it_behaves_like :transforming_immutable_data do
|
11
11
|
let(:input) { [] }
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "transproc/rspec"
|
4
|
+
|
5
|
+
describe AbstractMapper::Functions, "#identity" do
|
6
|
+
|
7
|
+
it_behaves_like :transforming_immutable_data do
|
8
|
+
let(:arguments) { [:identity] }
|
9
|
+
|
10
|
+
let(:input) { :foo }
|
11
|
+
let(:output) { :foo }
|
12
|
+
end
|
13
|
+
|
14
|
+
it_behaves_like :transforming_immutable_data do
|
15
|
+
let(:arguments) { [:identity, :bar, :baz] }
|
16
|
+
|
17
|
+
let(:input) { :foo }
|
18
|
+
let(:output) { :foo }
|
19
|
+
end
|
20
|
+
|
21
|
+
end # describe AbstractMapper::Functions#identity
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "transproc/rspec"
|
4
|
+
|
5
|
+
describe AbstractMapper::Functions, "#restrict" do
|
6
|
+
|
7
|
+
let(:arguments) { [:restrict, default] }
|
8
|
+
let(:default) { { foo: :FOO, bar: :BAR } }
|
9
|
+
|
10
|
+
it_behaves_like :transforming_immutable_data do
|
11
|
+
|
12
|
+
let(:input) { { foo: :BAZ, qux: :QUX } }
|
13
|
+
let(:output) { { foo: :BAZ, bar: :BAR } }
|
14
|
+
end
|
15
|
+
|
16
|
+
end # describe AbstractMapper::Functions#restrict
|