superstructure 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/superstructure/argument_error_builder.rb +27 -0
- data/lib/superstructure/attribute_parser.rb +45 -0
- data/lib/superstructure/value_obj.rb +15 -30
- data/lib/superstructure/version.rb +1 -1
- data/lib/superstructure.rb +2 -0
- data/spec/argument_error_builder_spec.rb +30 -0
- data/spec/value_obj_spec.rb +16 -6
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee6898266d56d163225dc8e36a560df58c775ad5
|
4
|
+
data.tar.gz: 0a54cd4233764e3709894e827a199cb4c6b250a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 235118a7fc7df08713a74f8e08ff6fd603f574e73ad1e28af21c25cdd449fa85e5d2a38274efc8c12dd8ae7e87ba1e72eace08ef9a604a9503c6c0192be53edf
|
7
|
+
data.tar.gz: 820253eeb35ff0c77c0572a9b4132c0c3eb7df7e6e70a6631abb2ebf99823a2834489df12ff3bc06acf5e1f079856228e90ff65516c2601dca782520b9fffbb3
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Superstructure
|
2
|
+
class ArgumentErrorBuilder
|
3
|
+
def initialize
|
4
|
+
@errors = {
|
5
|
+
extra_params: [],
|
6
|
+
missing_params: [],
|
7
|
+
shadowed_params: []
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_error(type, key)
|
12
|
+
add_errors(type, [key])
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_errors(type, key)
|
16
|
+
@errors.fetch(type).concat(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def build
|
20
|
+
ArgumentError.new(@errors)
|
21
|
+
end
|
22
|
+
|
23
|
+
def error?
|
24
|
+
@errors.any? { |k, v| v.any? }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Superstructure
|
2
|
+
class AttributeParser
|
3
|
+
attr_reader :attributes
|
4
|
+
|
5
|
+
def initialize(arguments, opts)
|
6
|
+
@attributes = {}
|
7
|
+
@possible_error = ArgumentErrorBuilder.new
|
8
|
+
@arguments = arguments
|
9
|
+
@opts = opts
|
10
|
+
|
11
|
+
parse!
|
12
|
+
end
|
13
|
+
|
14
|
+
def error?
|
15
|
+
@possible_error.error?
|
16
|
+
end
|
17
|
+
|
18
|
+
def error
|
19
|
+
@possible_error.build
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse!
|
25
|
+
used_params = []
|
26
|
+
|
27
|
+
@arguments.each do |argument|
|
28
|
+
if @opts.has_key?(argument) && @opts.has_key?(argument.to_s)
|
29
|
+
@possible_error.add_error(:shadowed_params, argument)
|
30
|
+
used_params << argument << argument.to_s
|
31
|
+
elsif @opts.has_key?(argument)
|
32
|
+
@attributes[argument] = @opts[argument]
|
33
|
+
used_params << argument
|
34
|
+
elsif @opts.has_key?(argument.to_s)
|
35
|
+
@attributes[argument] = @opts[argument.to_s]
|
36
|
+
used_params << argument.to_s
|
37
|
+
else
|
38
|
+
@possible_error.add_error(:missing_params, argument)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@possible_error.add_errors(:extra_params, @opts.keys - used_params)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -4,35 +4,11 @@ module Superstructure
|
|
4
4
|
def new *arguments, superclass: Object, &blk
|
5
5
|
Class.new(superclass) do
|
6
6
|
define_method(:initialize) do |opts={}|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
arguments.each do |argument|
|
13
|
-
if opts.has_key?(argument) && opts.has_key?(argument.to_s)
|
14
|
-
shadowed_params << argument
|
15
|
-
used_params << argument << argument.to_s
|
16
|
-
|
17
|
-
elsif opts.has_key?(argument)
|
18
|
-
@attributes[argument] = opts[argument]
|
19
|
-
used_params << argument
|
20
|
-
elsif opts.has_key?(argument.to_s)
|
21
|
-
@attributes[argument] = opts[argument.to_s]
|
22
|
-
used_params << argument.to_s
|
23
|
-
else
|
24
|
-
missing_params << argument
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
extra_params = opts.keys - used_params
|
29
|
-
|
30
|
-
if missing_params.any? || shadowed_params.any? || extra_params.any?
|
31
|
-
raise ArgumentError.new(
|
32
|
-
missing_params: missing_params,
|
33
|
-
shadowed_params: shadowed_params,
|
34
|
-
extra_params: extra_params
|
35
|
-
)
|
7
|
+
attribute_parser = AttributeParser.new(arguments, opts)
|
8
|
+
if attribute_parser.error?
|
9
|
+
raise attribute_parser.error
|
10
|
+
else
|
11
|
+
@attributes = attribute_parser.attributes
|
36
12
|
end
|
37
13
|
end
|
38
14
|
|
@@ -44,7 +20,12 @@ module Superstructure
|
|
44
20
|
opts = @attributes.map do |k, v|
|
45
21
|
"#{k}=#{v.inspect}"
|
46
22
|
end.join(", ")
|
47
|
-
|
23
|
+
|
24
|
+
unless opts.empty?
|
25
|
+
opts.prepend(" ")
|
26
|
+
end
|
27
|
+
|
28
|
+
"#<value_obj #{self.class}#{opts}>"
|
48
29
|
end
|
49
30
|
|
50
31
|
def ==(o)
|
@@ -53,6 +34,10 @@ module Superstructure
|
|
53
34
|
|
54
35
|
alias :eql? :==
|
55
36
|
|
37
|
+
def hash
|
38
|
+
self.class.hash ^ @attributes.hash
|
39
|
+
end
|
40
|
+
|
56
41
|
arguments.each do |argument|
|
57
42
|
define_method(argument) do
|
58
43
|
to_hash[argument]
|
data/lib/superstructure.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
RSpec.describe Superstructure::ArgumentErrorBuilder do
|
2
|
+
let(:builder) { described_class.new }
|
3
|
+
|
4
|
+
describe "#error?" do
|
5
|
+
subject { builder.error? }
|
6
|
+
|
7
|
+
context "when at least one error has been added" do
|
8
|
+
before do
|
9
|
+
builder.add_error(:missing_params, :hello)
|
10
|
+
end
|
11
|
+
|
12
|
+
it { should be_truthy }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when no errors have been added" do
|
16
|
+
it { should be_falsy }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "builds an ArgumentError with all of the added errors" do
|
21
|
+
builder.add_error(:extra_params, :alpha)
|
22
|
+
builder.add_errors(:missing_params, [:beta, :charlie])
|
23
|
+
|
24
|
+
expect(builder.build).to have_attributes(
|
25
|
+
extra_params: [:alpha],
|
26
|
+
missing_params: [:beta, :charlie],
|
27
|
+
shadowed_params: []
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
data/spec/value_obj_spec.rb
CHANGED
@@ -64,6 +64,12 @@ RSpec.describe Superstructure::ValueObj do
|
|
64
64
|
foobar = FooBar.new(foo: [:a, :b], bar: 2)
|
65
65
|
expect(foobar.inspect).to eq '#<value_obj FooBar foo=[:a, :b], bar=2>'
|
66
66
|
end
|
67
|
+
|
68
|
+
context "when there are no attributes" do
|
69
|
+
it "omits the attibutes" do
|
70
|
+
expect(Empty.new.inspect).to eq "#<value_obj Empty>"
|
71
|
+
end
|
72
|
+
end
|
67
73
|
end
|
68
74
|
|
69
75
|
it "can inherit from other classes" do
|
@@ -94,17 +100,17 @@ RSpec.describe Superstructure::ValueObj do
|
|
94
100
|
end
|
95
101
|
|
96
102
|
describe "equality" do
|
97
|
-
shared_examples_for "equality" do |
|
103
|
+
shared_examples_for "equality" do |sameness_proc|
|
98
104
|
it "is equal if all arguments are equal" do
|
99
105
|
alpha = FooBar.new(foo: 1, bar: 2)
|
100
106
|
beta = FooBar.new("foo" => 1, "bar" => 2)
|
101
|
-
expect(
|
107
|
+
expect(sameness_proc.(alpha, beta)).to be_truthy
|
102
108
|
end
|
103
109
|
|
104
110
|
it "is not equal if any argument doesn't equal" do
|
105
111
|
alpha = FooBar.new(foo: 1, bar: 2000)
|
106
112
|
beta = FooBar.new("foo" => 1, "bar" => 2)
|
107
|
-
expect(
|
113
|
+
expect(sameness_proc.(alpha, beta)).to be_falsey
|
108
114
|
end
|
109
115
|
|
110
116
|
it "is equal only to other instances of the same class" do
|
@@ -114,16 +120,20 @@ RSpec.describe Superstructure::ValueObj do
|
|
114
120
|
foobar = FooBar.new(opts)
|
115
121
|
barfoo = klass.new(opts)
|
116
122
|
|
117
|
-
expect(
|
123
|
+
expect(sameness_proc.(foobar, barfoo)).to be_falsey
|
118
124
|
end
|
119
125
|
end
|
120
126
|
|
121
127
|
describe "==" do
|
122
|
-
it_behaves_like "equality",
|
128
|
+
it_behaves_like "equality", proc { |a, b| a == b }
|
123
129
|
end
|
124
130
|
|
125
131
|
describe "eql?" do
|
126
|
-
it_behaves_like "equality",
|
132
|
+
it_behaves_like "equality", proc { |a, b| a.eql? b }
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "hash" do
|
136
|
+
it_behaves_like "equality", proc { |a, b| a.hash == b.hash }
|
127
137
|
end
|
128
138
|
end
|
129
139
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: superstructure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Finnie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -67,8 +67,11 @@ files:
|
|
67
67
|
- Rakefile
|
68
68
|
- lib/superstructure.rb
|
69
69
|
- lib/superstructure/argument_error.rb
|
70
|
+
- lib/superstructure/argument_error_builder.rb
|
71
|
+
- lib/superstructure/attribute_parser.rb
|
70
72
|
- lib/superstructure/value_obj.rb
|
71
73
|
- lib/superstructure/version.rb
|
74
|
+
- spec/argument_error_builder_spec.rb
|
72
75
|
- spec/argument_error_spec.rb
|
73
76
|
- spec/spec_helper.rb
|
74
77
|
- spec/value_obj_spec.rb
|
@@ -93,12 +96,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
96
|
version: '0'
|
94
97
|
requirements: []
|
95
98
|
rubyforge_project:
|
96
|
-
rubygems_version: 2.
|
99
|
+
rubygems_version: 2.5.2
|
97
100
|
signing_key:
|
98
101
|
specification_version: 4
|
99
102
|
summary: Immutable, keyword-argument based value objects for Ruby
|
100
103
|
test_files:
|
104
|
+
- spec/argument_error_builder_spec.rb
|
101
105
|
- spec/argument_error_spec.rb
|
102
106
|
- spec/spec_helper.rb
|
103
107
|
- spec/value_obj_spec.rb
|
104
|
-
has_rdoc:
|