sinclair 1.9.0 → 1.10.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/README.md +2 -2
  4. data/config/yardstick.yml +7 -1
  5. data/lib/sinclair/configurable.rb +2 -0
  6. data/lib/sinclair/equals_checker.rb +2 -0
  7. data/lib/sinclair/matchers/add_class_method.rb +27 -36
  8. data/lib/sinclair/matchers/add_instance_method.rb +59 -59
  9. data/lib/sinclair/matchers/add_method.rb +33 -35
  10. data/lib/sinclair/matchers/change_class_method.rb +22 -16
  11. data/lib/sinclair/matchers/change_instance_method.rb +46 -16
  12. data/lib/sinclair/matchers.rb +2 -8
  13. data/lib/sinclair/method_builder/call_method_builder.rb +49 -0
  14. data/lib/sinclair/method_builder.rb +4 -1
  15. data/lib/sinclair/method_definition/call_definition.rb +52 -0
  16. data/lib/sinclair/method_definition/string_definition.rb +0 -2
  17. data/lib/sinclair/method_definition.rb +40 -24
  18. data/lib/sinclair/method_definitions.rb +21 -1
  19. data/lib/sinclair/options/builder.rb +8 -0
  20. data/lib/sinclair/options.rb +1 -13
  21. data/lib/sinclair/version.rb +1 -1
  22. data/spec/integration/yard/sinclair/matchers/change_class_method_spec.rb +24 -0
  23. data/spec/integration/yard/sinclair/matchers/change_instance_method_spec.rb +40 -0
  24. data/spec/lib/sinclair/method_builder/call_method_builder_spec.rb +76 -0
  25. data/spec/lib/sinclair/method_builder_spec.rb +63 -20
  26. data/spec/lib/sinclair/method_definition/call_definition_spec.rb +36 -0
  27. data/spec/lib/sinclair/method_definition_spec.rb +64 -0
  28. data/spec/lib/sinclair/method_definitions_spec.rb +79 -0
  29. data/spec/lib/sinclair/options/builder_spec.rb +13 -0
  30. data/spec/lib/sinclair/options/class_methods_spec.rb +23 -8
  31. data/spec/support/shared_examples/attribute_accessor.rb +103 -0
  32. metadata +9 -2
@@ -5,8 +5,6 @@ class Sinclair
5
5
  # @api private
6
6
  # @author darthjee
7
7
  #
8
- # @abstract
9
- #
10
8
  # Define an instance method from string
11
9
  class StringDefinition < MethodDefinition
12
10
  # @param name [String,Symbol] name of the method
@@ -11,6 +11,7 @@ class Sinclair
11
11
  autoload :BlockHelper, 'sinclair/method_definition/block_helper'
12
12
  autoload :BlockDefinition, 'sinclair/method_definition/block_definition'
13
13
  autoload :StringDefinition, 'sinclair/method_definition/string_definition'
14
+ autoload :CallDefinition, 'sinclair/method_definition/call_definition'
14
15
 
15
16
  # @method name
16
17
  #
@@ -24,31 +25,46 @@ class Sinclair
24
25
  cached: false
25
26
  }.freeze
26
27
 
27
- # Builds a method that will return the same value always
28
- #
29
- # @return [Symbol]
30
- def self.default_value(method_name, value)
31
- define_method(method_name) { value }
32
- end
28
+ class << self
29
+ # Builds a method that will return the same value always
30
+ #
31
+ # @return [Symbol]
32
+ def default_value(method_name, value)
33
+ define_method(method_name) { value }
34
+ end
33
35
 
34
- # @param name [String,Symbol] name of the method
35
- # @param code [String] code to be evaluated as method
36
- # @param block [Proc] block with code to be added as method
37
- # @param options [Hash] Options of construction
38
- # @option options cached [Boolean] Flag telling to create a block
39
- # with cache
40
- #
41
- # builds a method definition based on arguments
42
- #
43
- # when block is given, returns a {BlockDefinition} and
44
- # returns a {StringDefinition} otherwise
45
- #
46
- # @return [Base]
47
- def self.from(name, code = nil, **options, &block)
48
- if block
49
- BlockDefinition.new(name, **options, &block)
50
- else
51
- StringDefinition.new(name, code, **options)
36
+ # @param name [String,Symbol] name of the method
37
+ # @param code [String] code to be evaluated as method
38
+ # @param block [Proc] block with code to be added as method
39
+ # @param options [Hash] Options of construction
40
+ # @option options cached [Boolean] Flag telling to create a block
41
+ # with cache
42
+ #
43
+ # builds a method definition based on arguments
44
+ #
45
+ # when block is given, returns a {BlockDefinition} and
46
+ # returns a {StringDefinition} otherwise
47
+ #
48
+ # @return [Base]
49
+ def from(name, code = nil, **options, &block)
50
+ if block
51
+ BlockDefinition.new(name, **options, &block)
52
+ else
53
+ StringDefinition.new(name, code, **options)
54
+ end
55
+ end
56
+
57
+ # creates a definition
58
+ #
59
+ # The creation is based on type which will be used to infer
60
+ # which subclass of {Sinclair::MethodDefinition} to be used
61
+ #
62
+ # @param type [Symbol] the method definition type
63
+ #
64
+ # @return [Sinclair::MethodDefinition] an instance of a subclass
65
+ def for(type, *args, **options, &block)
66
+ klass = const_get("#{type}_definition".camelize)
67
+ klass.new(*args, **options, &block)
52
68
  end
53
69
  end
54
70
 
@@ -10,6 +10,8 @@ class Sinclair
10
10
 
11
11
  # Builds and adds new definition
12
12
  #
13
+ # The type is decided based in the arguments
14
+ #
13
15
  # @param name [String,Symbol] method name
14
16
  # @param options [Hash] Options of construction
15
17
  # @option options cached [Boolean] Flag telling to create
@@ -21,11 +23,29 @@ class Sinclair
21
23
  # @overload add(definition_class, name, **options, &block)
22
24
  # @param block [Proc] block to be ran as method
23
25
  #
24
- # @return MethodDefinitions
26
+ # @return [Array<MethodDefinition>]
25
27
  def add(name, code = nil, **options, &block)
26
28
  definitions << MethodDefinition.from(name, code, **options, &block)
27
29
  end
28
30
 
31
+ # Builds and adds new definition
32
+ #
33
+ # The type is decided based on the argument +type+
34
+ #
35
+ # @param type [Symbol] type of definition
36
+ # - :string -> {MethodDefinition::StringDefinition}
37
+ # - :block -> {MethodDefinition::BlockDefinition}
38
+ # - :call -> {MethodDefinition::CallDefinition}
39
+ # @param options [Hash] Options of construction
40
+ # @option options cached [Boolean] Flag telling to create
41
+ # a method with cache
42
+ # @param block [Proc] block to be ran as method
43
+ #
44
+ # @return [Array<MethodDefinition>]
45
+ def add_definition(type, *args, **options, &block)
46
+ definitions << MethodDefinition.for(type, *args, **options, &block)
47
+ end
48
+
29
49
  private
30
50
 
31
51
  # @private
@@ -36,6 +36,7 @@ class Sinclair
36
36
  # @return (see Sinclair#build)
37
37
  def build
38
38
  add_all_methods
39
+ add_filds_to_equals
39
40
 
40
41
  super
41
42
  end
@@ -60,6 +61,13 @@ class Sinclair
60
61
  klass.allow(option)
61
62
  end
62
63
  end
64
+
65
+ # Add the fields to equals comparation
66
+ #
67
+ # @return (see Sinclair::EqualsChecker#add)
68
+ def add_filds_to_equals
69
+ klass.comparable_by(*attributes.keys)
70
+ end
63
71
  end
64
72
  end
65
73
  end
@@ -24,6 +24,7 @@ class Sinclair
24
24
  autoload :ClassMethods, 'sinclair/options/class_methods'
25
25
 
26
26
  extend ClassMethods
27
+ include Comparable
27
28
 
28
29
  # @param options [Hash] hash with options (see {.options}, {.with_options})
29
30
  # @example (see Options)
@@ -59,19 +60,6 @@ class Sinclair
59
60
  end
60
61
  end
61
62
 
62
- # returns if other equals to self
63
- #
64
- # @param other [Object] object to be compared
65
- #
66
- # @return [TrueClass,FalseClass]
67
- def ==(other)
68
- return false unless self.class == other.class
69
-
70
- allowed_options.all? do |name|
71
- public_send(name) == other.public_send(name)
72
- end
73
- end
74
-
75
63
  private
76
64
 
77
65
  delegate :allowed_options, :skip_validation?, :invalid_options_in, to: :class
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.9.0'
4
+ VERSION = '1.10.0'
5
5
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Sinclair::Matchers::ChangeClassMethod do
6
+ describe 'yard' do
7
+ describe '#on' do
8
+ context 'when checking against Class' do
9
+ let(:klass) { Class.new(MyModel) }
10
+ let(:builder) { Sinclair.new(klass) }
11
+
12
+ before do
13
+ builder.add_class_method(:the_method) { 10 }
14
+ builder.build
15
+ builder.add_class_method(:the_method) { 20 }
16
+ end
17
+
18
+ it do
19
+ expect { builder.build }.to change_class_method(:the_method).on(klass)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Sinclair::Matchers::ChangeInstanceMethod do
6
+ describe 'yard' do
7
+ describe '#on' do
8
+ context 'when checking against Class' do
9
+ let(:klass) { Class.new(MyModel) }
10
+ let(:builder) { Sinclair.new(klass) }
11
+
12
+ before do
13
+ builder.add_method(:the_method) { 10 }
14
+ builder.build
15
+ builder.add_method(:the_method) { 20 }
16
+ end
17
+
18
+ it do
19
+ expect { builder.build }.to change_method(:the_method).on(klass)
20
+ end
21
+ end
22
+
23
+ context 'when checking against an intance' do
24
+ let(:klass) { Class.new(MyModel) }
25
+ let(:instance) { klass.new }
26
+ let(:builder) { Sinclair.new(klass) }
27
+
28
+ before do
29
+ builder.add_method(:the_method) { 10 }
30
+ builder.build
31
+ builder.add_method(:the_method) { 20 }
32
+ end
33
+
34
+ it do
35
+ expect { builder.build }.to change_method(:the_method).on(instance)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::MethodBuilder::CallMethodBuilder do
6
+ describe '#build' do
7
+ subject(:builder) do
8
+ described_class.new(klass, definition, type: type)
9
+ end
10
+
11
+ let(:call_name) { "attr_#{accessor_type}" }
12
+
13
+ let(:definition) do
14
+ Sinclair::MethodDefinition::CallDefinition.new(call_name, *attributes)
15
+ end
16
+
17
+ context 'when method called is attr_accessor' do
18
+ let(:accessor_type) { :accessor }
19
+
20
+ it_behaves_like 'a method builder that adds attribute reader'
21
+ it_behaves_like 'a method builder that adds attribute writer'
22
+ end
23
+
24
+ context 'when method called is attr_reader' do
25
+ let(:accessor_type) { :reader }
26
+
27
+ it_behaves_like 'a method builder that adds attribute reader' do
28
+ context 'when type is instance' do
29
+ let(:type) { Sinclair::MethodBuilder::INSTANCE_METHOD }
30
+
31
+ it 'does not add a reader' do
32
+ expect { builder.build }
33
+ .not_to add_method("#{method_name}=")
34
+ .to(instance)
35
+ end
36
+ end
37
+
38
+ context 'when type is class' do
39
+ let(:type) { Sinclair::MethodBuilder::CLASS_METHOD }
40
+
41
+ it 'does not add a reader' do
42
+ expect { builder.build }
43
+ .not_to add_class_method("#{method_name}=")
44
+ .to(klass)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'when method called is attr_writter' do
51
+ let(:accessor_type) { :writer }
52
+
53
+ it_behaves_like 'a method builder that adds attribute writer' do
54
+ context 'when type is instance' do
55
+ let(:type) { Sinclair::MethodBuilder::INSTANCE_METHOD }
56
+
57
+ it 'does not add a reader' do
58
+ expect { builder.build }
59
+ .not_to add_method(method_name)
60
+ .to(instance)
61
+ end
62
+ end
63
+
64
+ context 'when type is class' do
65
+ let(:type) { Sinclair::MethodBuilder::CLASS_METHOD }
66
+
67
+ it 'does not add a reader' do
68
+ expect { builder.build }
69
+ .not_to add_class_method(method_name)
70
+ .to(klass)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -11,41 +11,84 @@ describe Sinclair::MethodBuilder do
11
11
  let(:method_name) { :the_method }
12
12
  let(:instance) { klass.new }
13
13
 
14
- before do
15
- definitions.add(method_name, value.to_s)
16
- end
17
-
18
14
  describe '#build_methods' do
19
- context 'when building an instance method' do
20
- let(:type) { described_class::INSTANCE_METHOD }
15
+ context 'when the method is a string definition' do
16
+ before do
17
+ definitions.add(method_name, value.to_s)
18
+ end
21
19
 
22
- it do
23
- expect { builder.build_methods(definitions, type) }
24
- .to add_method(method_name).to(instance)
20
+ context 'when building an instance method' do
21
+ let(:type) { described_class::INSTANCE_METHOD }
22
+
23
+ it do
24
+ expect { builder.build_methods(definitions, type) }
25
+ .to add_method(method_name).to(instance)
26
+ end
27
+
28
+ context 'when the method is called' do
29
+ before { builder.build_methods(definitions, type) }
30
+
31
+ it do
32
+ expect(instance.the_method).to eq(value)
33
+ end
34
+ end
25
35
  end
26
36
 
27
- context 'when the method is called' do
28
- before { builder.build_methods(definitions, type) }
37
+ context 'when building a class method' do
38
+ let(:type) { described_class::CLASS_METHOD }
29
39
 
30
40
  it do
31
- expect(instance.the_method).to eq(value)
41
+ expect { builder.build_methods(definitions, type) }
42
+ .to add_class_method(method_name).to(klass)
43
+ end
44
+
45
+ context 'when the method is called' do
46
+ before { builder.build_methods(definitions, type) }
47
+
48
+ it do
49
+ expect(klass.the_method).to eq(value)
50
+ end
32
51
  end
33
52
  end
34
53
  end
35
54
 
36
- context 'when building a class method' do
37
- let(:type) { described_class::CLASS_METHOD }
55
+ context 'when the method is a block definition' do
56
+ before do
57
+ result = value
58
+ definitions.add(method_name) { result }
59
+ end
60
+
61
+ context 'when building an instance method' do
62
+ let(:type) { described_class::INSTANCE_METHOD }
63
+
64
+ it do
65
+ expect { builder.build_methods(definitions, type) }
66
+ .to add_method(method_name).to(instance)
67
+ end
38
68
 
39
- it do
40
- expect { builder.build_methods(definitions, type) }
41
- .to add_class_method(method_name).to(klass)
69
+ context 'when the method is called' do
70
+ before { builder.build_methods(definitions, type) }
71
+
72
+ it do
73
+ expect(instance.the_method).to eq(value)
74
+ end
75
+ end
42
76
  end
43
77
 
44
- context 'when the method is called' do
45
- before { builder.build_methods(definitions, type) }
78
+ context 'when building a class method' do
79
+ let(:type) { described_class::CLASS_METHOD }
46
80
 
47
81
  it do
48
- expect(klass.the_method).to eq(value)
82
+ expect { builder.build_methods(definitions, type) }
83
+ .to add_class_method(method_name).to(klass)
84
+ end
85
+
86
+ context 'when the method is called' do
87
+ before { builder.build_methods(definitions, type) }
88
+
89
+ it do
90
+ expect(klass.the_method).to eq(value)
91
+ end
49
92
  end
50
93
  end
51
94
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::MethodDefinition::CallDefinition do
6
+ subject(:definition) do
7
+ described_class.new(call_name, *attributes)
8
+ end
9
+
10
+ let(:call_name) { :method_call }
11
+ let(:attributes) { %i[key1 value2] }
12
+
13
+ describe '#code_string' do
14
+ let(:expected) { 'method_call :key1, :value2' }
15
+
16
+ it 'returns the code string' do
17
+ expect(definition.code_string)
18
+ .to eq(expected)
19
+ end
20
+ end
21
+
22
+ describe '#class_code_string' do
23
+ let(:expected) do
24
+ <<-RUBY
25
+ class << self
26
+ method_call :key1, :value2
27
+ end
28
+ RUBY
29
+ end
30
+
31
+ it 'returns the code string' do
32
+ expect(definition.class_code_string.gsub(/^ */, ''))
33
+ .to eq(expected.gsub(/^ */, ''))
34
+ end
35
+ end
36
+ end
@@ -42,4 +42,68 @@ describe Sinclair::MethodDefinition do
42
42
  end
43
43
  end
44
44
  end
45
+
46
+ describe '.for' do
47
+ context 'when there are no options nor block' do
48
+ let(:type) { :call }
49
+ let(:arguments) { %i[attr_reader some_attribute other_attribute] }
50
+
51
+ it do
52
+ expect(described_class.for(type, *arguments))
53
+ .to be_a(described_class)
54
+ end
55
+
56
+ it 'Returns an instance of the given type' do
57
+ expect(described_class.for(type, *arguments))
58
+ .to be_a(described_class::CallDefinition)
59
+ end
60
+
61
+ it 'initializes it correctly' do
62
+ expect(described_class.for(type, *arguments).code_string)
63
+ .to eq('attr_reader :some_attribute, :other_attribute')
64
+ end
65
+ end
66
+
67
+ context 'when a block is given' do
68
+ let(:type) { :block }
69
+ let(:method_name) { :the_method }
70
+ let(:block) { proc { 10 } }
71
+
72
+ it do
73
+ expect(described_class.for(type, method_name, &block))
74
+ .to be_a(described_class)
75
+ end
76
+
77
+ it 'Returns an instance of the given type' do
78
+ expect(described_class.for(type, method_name, &block))
79
+ .to be_a(described_class::BlockDefinition)
80
+ end
81
+
82
+ it 'initializes it correctly' do
83
+ expect(described_class.for(type, method_name, &block).name)
84
+ .to eq(method_name)
85
+ end
86
+ end
87
+
88
+ context 'when options are given' do
89
+ let(:type) { :string }
90
+ let(:method_name) { :the_method }
91
+ let(:code) { '10' }
92
+
93
+ it do
94
+ expect(described_class.for(type, method_name, code))
95
+ .to be_a(described_class)
96
+ end
97
+
98
+ it 'Returns an instance of the given type' do
99
+ expect(described_class.for(type, method_name, code))
100
+ .to be_a(described_class::StringDefinition)
101
+ end
102
+
103
+ it 'initializes it correctly' do
104
+ expect(described_class.for(type, method_name, code).name)
105
+ .to eq(method_name)
106
+ end
107
+ end
108
+ end
45
109
  end
@@ -42,4 +42,83 @@ describe Sinclair::MethodDefinitions do
42
42
  end
43
43
  end
44
44
  end
45
+
46
+ describe '#add_definition' do
47
+ context 'when there are no options nor block' do
48
+ let(:type) { :call }
49
+ let(:arguments) { %i[attr_reader some_attribute other_attribute] }
50
+
51
+ it do
52
+ expect(definitions.add_definition(type, *arguments))
53
+ .to be_a(Array)
54
+ end
55
+
56
+ it 'creates a new definition' do
57
+ expect(definitions.add_definition(type, *arguments).last)
58
+ .to be_a(Sinclair::MethodDefinition)
59
+ end
60
+
61
+ it 'creates a new definition of the chosen type' do
62
+ expect(definitions.add_definition(type, *arguments).last)
63
+ .to be_a(Sinclair::MethodDefinition::CallDefinition)
64
+ end
65
+
66
+ it 'initializes it correctly' do
67
+ expect(definitions.add_definition(type, *arguments).last.code_string)
68
+ .to eq('attr_reader :some_attribute, :other_attribute')
69
+ end
70
+ end
71
+
72
+ context 'when a block is given' do
73
+ let(:type) { :block }
74
+ let(:method_name) { :the_method }
75
+ let(:block) { proc { 10 } }
76
+
77
+ it do
78
+ expect(definitions.add_definition(type, method_name, &block))
79
+ .to be_a(Array)
80
+ end
81
+
82
+ it 'creates a new definition' do
83
+ expect(definitions.add_definition(type, method_name, &block).last)
84
+ .to be_a(Sinclair::MethodDefinition)
85
+ end
86
+
87
+ it 'creates a new definition of the chosen type' do
88
+ expect(definitions.add_definition(type, method_name, &block).last)
89
+ .to be_a(Sinclair::MethodDefinition::BlockDefinition)
90
+ end
91
+
92
+ it 'initializes it correctly' do
93
+ expect(definitions.add_definition(type, method_name, &block).last.name)
94
+ .to eq(method_name)
95
+ end
96
+ end
97
+
98
+ context 'when options are given' do
99
+ let(:type) { :string }
100
+ let(:method_name) { :the_method }
101
+ let(:code) { '10' }
102
+
103
+ it do
104
+ expect(definitions.add_definition(type, method_name, code))
105
+ .to be_a(Array)
106
+ end
107
+
108
+ it 'creates a new definition' do
109
+ expect(definitions.add_definition(type, method_name, code).last)
110
+ .to be_a(Sinclair::MethodDefinition)
111
+ end
112
+
113
+ it 'creates a new definition of the chosen type' do
114
+ expect(definitions.add_definition(type, method_name, code).last)
115
+ .to be_a(Sinclair::MethodDefinition::StringDefinition)
116
+ end
117
+
118
+ it 'initializes it correctly' do
119
+ expect(definitions.add_definition(type, method_name, code).last.name)
120
+ .to eq(method_name)
121
+ end
122
+ end
123
+ end
45
124
  end
@@ -40,6 +40,19 @@ describe Sinclair::Options::Builder do
40
40
  .not_to change { Sinclair::Options.invalid_options_in(test_keys) }
41
41
  end
42
42
 
43
+ context 'when the object is compared with others' do
44
+ before { klass.skip_validation }
45
+
46
+ let(:options1) { klass.new(timeout: 10) }
47
+ let(:options2) { klass.new(timeout: 15) }
48
+
49
+ it 'adds the field to the equals check' do
50
+ expect { builder.build }
51
+ .to change { options1 == options2 }
52
+ .from(true).to(false)
53
+ end
54
+ end
55
+
43
56
  context 'when when calling method after building' do
44
57
  before { builder.build }
45
58