sinclair 1.3.0 → 1.3.1

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.
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ class MethodDefinition
5
+ # Define a method from block
6
+ class BlockDefinition < MethodDefinition
7
+ # @param name [String,Symbol] name of the method
8
+ # @param block [Proc] block with code to be added as method
9
+ # @param options [Hash] Options of construction
10
+ # @option options cached [Boolean] Flag telling to create
11
+ # a method with cache
12
+ def initialize(name, **options, &block)
13
+ @block = block
14
+ super(name, **options)
15
+ end
16
+
17
+ # Adds the method to given klass
18
+ #
19
+ # @param klass [Class] class which will receive the new method
20
+ #
21
+ # @see MethodDefinition#build
22
+ #
23
+ # @return [Symbol] name of the created method
24
+ #
25
+ # @example Using block method with no options
26
+ # class MyModel
27
+ # end
28
+ #
29
+ # instance = MyModel.new
30
+ #
31
+ # method_definition = Sinclair::MethodDefinition::BlockDefinition.new(:sequence) do
32
+ # @x = @x.to_i ** 2 + 1
33
+ # end
34
+ #
35
+ # method_definition.build(klass) # adds instance_method :sequence to
36
+ # # MyModel instances
37
+ #
38
+ # instance.instance_variable_get(:@sequence) # returns nil
39
+ # instance.instance_variable_get(:@x) # returns nil
40
+ #
41
+ # instance.sequence # returns 1
42
+ # instance.sequence # returns 1 (cached value)
43
+ #
44
+ # instance.instance_variable_get(:@sequence) # returns 1
45
+ # instance.instance_variable_get(:@x) # returns 1
46
+ def build(klass)
47
+ klass.send(:define_method, name, method_block)
48
+ end
49
+
50
+ private
51
+
52
+ # @private
53
+ #
54
+ # Returns the block that will be used for method creattion
55
+ #
56
+ # @return [Proc]
57
+ def method_block
58
+ return block unless cached?
59
+
60
+ case cached
61
+ when :full
62
+ full_cached_method_proc(name, block)
63
+ else
64
+ cached_method_proc(name, block)
65
+ end
66
+ end
67
+
68
+ # @private
69
+ #
70
+ # Returns proc block when {#cached?} as simple
71
+ #
72
+ # @return [Proc]
73
+ def cached_method_proc(method_name, inner_block)
74
+ proc do
75
+ instance_variable_get("@#{method_name}") ||
76
+ instance_variable_set(
77
+ "@#{method_name}",
78
+ instance_eval(&inner_block)
79
+ )
80
+ end
81
+ end
82
+
83
+ # @private
84
+ #
85
+ # Returns proc block when {#cached?} as full
86
+ #
87
+ # @return [Proc]
88
+ def full_cached_method_proc(method_name, inner_block)
89
+ proc do
90
+ if instance_variable_defined?("@#{method_name}")
91
+ instance_variable_get("@#{method_name}")
92
+ else
93
+ instance_variable_set(
94
+ "@#{method_name}",
95
+ instance_eval(&inner_block)
96
+ )
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ class MethodDefinition
5
+ # Define a method from string
6
+ class StringDefinition < MethodDefinition
7
+ # @param name [String,Symbol] name of the method
8
+ # @param code [String] code to be evaluated as method
9
+ # @param options [Hash] Options of construction
10
+ # @option options cached [Boolean] Flag telling to create
11
+ # a method with cache
12
+ def initialize(name, code = nil, **options)
13
+ @code = code
14
+ super(name, **options)
15
+ end
16
+
17
+ # Adds the method to given klass
18
+ #
19
+ # @param klass [Class] class which will receive the new method
20
+ #
21
+ # @see MethodDefinition#build
22
+ #
23
+ # @return [Symbol] name of the created method
24
+ #
25
+ # @example With no options
26
+ # class MyModel
27
+ # end
28
+ #
29
+ # instance = MyModel.new
30
+ #
31
+ # method_definition = Sinclair::MethodDefinition.from(
32
+ # :sequence, '@x = @x.to_i ** 2 + 1'
33
+ # )
34
+ #
35
+ # method_definition.build(klass) # adds instance_method :sequence to
36
+ # # MyModel instances
37
+ #
38
+ # instance.instance_variable_get(:@x) # returns nil
39
+ #
40
+ # instance.sequence # returns 1
41
+ # instance.sequence # returns 2
42
+ # instance.sequence # returns 5
43
+ #
44
+ # instance.instance_variable_get(:@x) # returns 5
45
+ #
46
+ def build(klass)
47
+ klass.module_eval(code_definition, __FILE__, __LINE__ + 1)
48
+ end
49
+
50
+ private
51
+
52
+ # @private
53
+ #
54
+ # Builds full code of method
55
+ #
56
+ # @return [String]
57
+ def code_definition
58
+ code_line = cached? ? code_with_cache : code
59
+
60
+ <<-CODE
61
+ def #{name}
62
+ #{code_line}
63
+ end
64
+ CODE
65
+ end
66
+
67
+ # @private
68
+ #
69
+ # Returns string code when {#cached?}
70
+ #
71
+ # @return [String]
72
+ def code_with_cache
73
+ case cached
74
+ when :full
75
+ "defined?(@#{name}) ? @#{name} : (@#{name} = #{code})"
76
+ else
77
+ "@#{name} ||= #{code}"
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.3.0'
4
+ VERSION = '1.3.1'
5
5
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Configurable do
6
+ context 'when it is configured' do
7
+ before do
8
+ MyConfigurable.configure do |config|
9
+ config.host 'interstella.art'
10
+ config.port 5555
11
+ end
12
+ end
13
+
14
+ after do
15
+ MyConfigurable.reset_config
16
+ end
17
+
18
+ it 'sets configuration host' do
19
+ expect(MyConfigurable.config.host)
20
+ .to eq('interstella.art')
21
+ end
22
+
23
+ it 'sets configuration port' do
24
+ expect(MyConfigurable.config.port)
25
+ .to eq(5555)
26
+ end
27
+
28
+ context 'when #rest_config is called' do
29
+ before do
30
+ MyConfigurable.reset_config
31
+ end
32
+
33
+ it 'resets configuration host' do
34
+ expect(MyConfigurable.config.host)
35
+ .to be_nil
36
+ end
37
+
38
+ it 'resets configuration port' do
39
+ expect(MyConfigurable.config.port)
40
+ .to be_nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -22,4 +22,74 @@ describe Sinclair do
22
22
  expect("Eighty => #{instance.eighty}").to eq('Eighty => 80')
23
23
  end
24
24
  end
25
+
26
+ describe 'Stand Alone concern' do
27
+ subject(:person) { HttpPerson.new(json) }
28
+
29
+ let(:json) do
30
+ <<-JSON
31
+ {
32
+ "uid": "12sof511",
33
+ "personal_information":{
34
+ "name":"Bob",
35
+ "age": 21
36
+ },
37
+ "digital_information":{
38
+ "username":"lordbob",
39
+ "email":"lord@bob.com"
40
+ }
41
+ }
42
+ JSON
43
+ end
44
+
45
+ it 'adds uid method' do
46
+ expect(person.uid).to eq('12sof511')
47
+ end
48
+
49
+ it 'adds name method' do
50
+ expect(person.name).to eq('Bob')
51
+ end
52
+
53
+ it 'adds age method' do
54
+ expect(person.age).to eq(21)
55
+ end
56
+
57
+ it 'adds username method' do
58
+ expect(person.username).to eq('lordbob')
59
+ end
60
+
61
+ it 'adds email method' do
62
+ expect(person.email).to eq('lord@bob.com')
63
+ end
64
+ end
65
+
66
+ describe 'DefaultValuable' do
67
+ subject(:server) { Server.new }
68
+
69
+ it 'returns default url' do
70
+ expect(server.url).to eq('http://server.com:80')
71
+ end
72
+
73
+ context 'when new values are set' do
74
+ before do
75
+ server.host = 'interstella.com'
76
+ server.port = 5555
77
+ end
78
+
79
+ it 'returns custom url' do
80
+ expect(server.url).to eq('http://interstella.com:5555')
81
+ end
82
+
83
+ context 'when values are nullified' do
84
+ before do
85
+ server.host = nil
86
+ server.port = nil
87
+ end
88
+
89
+ it 'returns url with default + custom nil values' do
90
+ expect(server.url).to eq('http://server.com')
91
+ end
92
+ end
93
+ end
94
+ end
25
95
  end
@@ -9,6 +9,10 @@ describe Sinclair::Configurable do
9
9
  end
10
10
  end
11
11
 
12
+ after do
13
+ MyConfigurable.reset_config
14
+ end
15
+
12
16
  it 'sets right value for config host' do
13
17
  expect(MyConfigurable.config.host)
14
18
  .to eq('interstella.com')
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Sinclair::MethodDefinition::BlockDefinition do
4
+ describe 'yard' do
5
+ describe '#build' do
6
+ subject(:method_definition) do
7
+ described_class.from(name, cached: true) do
8
+ @x = @x.to_i**2 + 1
9
+ end
10
+ end
11
+
12
+ let(:klass) { Class.new }
13
+ let(:instance) { klass.new }
14
+ let(:name) { :sequence }
15
+
16
+ it 'adds a dynamic method' do
17
+ expect { method_definition.build(klass) }.to add_method(name).to(instance)
18
+ expect { instance.sequence }
19
+ .to change { instance.instance_variable_get(:@x) }.from(nil).to(1)
20
+ expect { instance.sequence }.not_to change(instance, :sequence)
21
+ expect(instance.instance_variable_get(:@sequence)).to eq(1)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Sinclair::MethodDefinition::StringDefinition do
4
+ describe 'yard' do
5
+ describe '#build' do
6
+ subject(:method_definition) do
7
+ described_class.new(name, code)
8
+ end
9
+
10
+ let(:klass) { Class.new }
11
+ let(:instance) { klass.new }
12
+ let(:code) { '@x = @x.to_i ** 2 + 1' }
13
+ let(:name) { :sequence }
14
+
15
+ it 'adds a dynamic method' do
16
+ expect { method_definition.build(klass) }.to add_method(name).to(instance)
17
+ expect { instance.sequence }
18
+ .to change { instance.instance_variable_get(:@x) }.from(nil).to 1
19
+ expect(instance.sequence).to eq(2)
20
+ expect(instance.sequence).to eq(5)
21
+ end
22
+
23
+ it 'changes instance variable' do
24
+ method_definition.build(klass)
25
+
26
+ expect { instance.sequence }
27
+ .to change { instance.instance_variable_get(:@x) }
28
+ .from(nil).to 1
29
+ end
30
+ end
31
+ end
32
+ end
@@ -5,7 +5,7 @@ describe Sinclair::MethodDefinition do
5
5
  describe '#build' do
6
6
  describe 'using string method with no options' do
7
7
  subject(:method_definition) do
8
- described_class.new(name, code)
8
+ described_class.from(name, code)
9
9
  end
10
10
 
11
11
  let(:klass) { Class.new }
@@ -32,7 +32,7 @@ describe Sinclair::MethodDefinition do
32
32
 
33
33
  describe 'using block with cache option' do
34
34
  subject(:method_definition) do
35
- described_class.new(name, cached: true) do
35
+ described_class.from(name, cached: true) do
36
36
  @x = @x.to_i**2 + 1
37
37
  end
38
38
  end
@@ -9,6 +9,36 @@ describe Sinclair do
9
9
  let(:builder) { described_class.new(klass) }
10
10
  let(:default_value) { 10 }
11
11
 
12
+ describe 'Using cache' do
13
+ subject(:server) { Server.new }
14
+
15
+ it 'returns default url' do
16
+ expect(server.url).to eq('http://server.com:80')
17
+ end
18
+
19
+ context 'when new values are set' do
20
+ before do
21
+ server.host = 'interstella.com'
22
+ server.port = 5555
23
+ end
24
+
25
+ it 'returns custom url' do
26
+ expect(server.url).to eq('http://interstella.com:5555')
27
+ end
28
+
29
+ context 'when values are nullified' do
30
+ before do
31
+ server.host = nil
32
+ server.port = nil
33
+ end
34
+
35
+ it 'returns url with default + custom nil values' do
36
+ expect(server.url).to eq('http://server.com')
37
+ end
38
+ end
39
+ end
40
+ end
41
+
12
42
  describe '#initialize' do
13
43
  describe '#total_price' do
14
44
  before do
@@ -39,6 +39,16 @@ describe Sinclair::Matchers::AddMethodTo do
39
39
  it { expect(matcher).to be_matches(event_proc) }
40
40
  end
41
41
  end
42
+
43
+ context 'when a block is given' do
44
+ it do
45
+ expect { matcher.matches?(event_proc) { 1 } }
46
+ .to raise_error(
47
+ SyntaxError, 'Block not received by the `add_method_to` matcher. ' \
48
+ 'Perhaps you want to use `{ ... }` instead of do/end?'
49
+ )
50
+ end
51
+ end
42
52
  end
43
53
 
44
54
  describe '#failure_message_for_should' do