sinclair 1.12.0 → 1.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a194ca690bacbcb4a928dc5295a60f6e574b6cf567cc81ab33a293dbe9d3643
4
- data.tar.gz: 77d34d971fee05045d57e73939a0a299707cad027bb770c09e348ca35fb76bce
3
+ metadata.gz: 46b430c9db3658979d128e45ecbbb03aab30bb993d8651ecc8cc3bd9fe1b18e3
4
+ data.tar.gz: fa78aa3bde540b7f90675566086e65d884cea51b2874b6cd5166ffc50018ab73
5
5
  SHA512:
6
- metadata.gz: aa8cc30f12639711e53e3e2396fa59075ea59673fb49469be8ad757f8502b75ed07df9b57a0a4c863dd0067b1cd655455bdf649189318d04a71f8c758af7c7d5
7
- data.tar.gz: 29942c828c7621d728307f16731fbc5ac715371512e35a8872d9f6102b07c54256a4571e0324cc82e69703d7b75a6ce87b2658ff26ef54886b69bc0d15a3f6ec
6
+ metadata.gz: 9a290bcea44d39854bd7b8bd99b28c18d0a6c827b31f140fb339b82d49a9add6e505f738b4925b27c25ddedd695d06963a4221c55ff9b869157aaec5753a5747
7
+ data.tar.gz: dfdc3723b6a6d31611eceb727007680aafc3f56d9cda1e16922768df7e9ce14238d0c982ff7e4232a914015c8d22850b869ab08601b8121727ce0673c43ca10b
data/.rubocop.yml CHANGED
@@ -4,7 +4,6 @@ inherit_from: .rubocop_todo.yml
4
4
  AllCops:
5
5
  TargetRubyVersion: 2.5
6
6
 
7
-
8
7
  RSpec/DescribeClass:
9
8
  Exclude:
10
9
  - 'spec/integration/yard/**/*_spec.rb'
data/README.md CHANGED
@@ -13,13 +13,13 @@ This gem helps the creation of complex gems/concerns
13
13
  that enables creation of methods on the fly through class
14
14
  methods
15
15
 
16
- Current Release: [1.12.0](https://github.com/darthjee/sinclair/tree/1.12.0)
16
+ Current Release: [1.13.0](https://github.com/darthjee/sinclair/tree/1.13.0)
17
17
 
18
- [Next release](https://github.com/darthjee/sinclair/compare/1.12.0...master)
18
+ [Next release](https://github.com/darthjee/sinclair/compare/1.13.0...master)
19
19
 
20
20
  Yard Documentation
21
21
  -------------------
22
- [https://www.rubydoc.info/gems/sinclair/1.12.0](https://www.rubydoc.info/gems/sinclair/1.12.0)
22
+ [https://www.rubydoc.info/gems/sinclair/1.13.0](https://www.rubydoc.info/gems/sinclair/1.13.0)
23
23
 
24
24
  Installation
25
25
  ---------------
@@ -616,6 +616,44 @@ model1 == model2 # returns true
616
616
  ```
617
617
  </details>
618
618
 
619
+ ### Sinclair::Model
620
+ Model class for quickly creation of plain simple classes/models
621
+
622
+ When creating a model class, options can be passed
623
+ - writter: Adds writter/setter methods (defaults to true)
624
+ - comparable: Adds the fields when running a `==` method (defaults to true)
625
+
626
+ <details>
627
+ <summary>Example of simple usage</summary>
628
+
629
+ ```ruby
630
+ class Human < Sinclair::Model.for(:name, :age, { gender: :undefined }, **{})
631
+ end
632
+
633
+ human1 = Human.new(name: 'John Doe', age: 22)
634
+ human2 = Human.new(name: 'John Doe', age: 22)
635
+
636
+ human1.name # returns 'John Doe'
637
+ human1.age # returns 22
638
+ human1.gender # returns :undefined
639
+ human1 == human2 # returns true
640
+ ```
641
+ </details>
642
+
643
+ <details>
644
+ <summary>Example with options</summary>
645
+
646
+ ```ruby
647
+ class Tv < Sinclair::Model.for(:model, writter: false, comparable: false)
648
+ end
649
+
650
+ tv1 = Tv.new(model: 'Sans Sunga Xt')
651
+ tv2 = Tv.new(model: 'Sans Sunga Xt')
652
+
653
+ tv1 == tv2 # returns false
654
+ ```
655
+ </details>
656
+
619
657
  RSspec matcher
620
658
  ---------------
621
659
 
@@ -1,4 +1,5 @@
1
1
  ignore:
2
+ - lib/sinclair/model/builder.rb
2
3
  - lib/sinclair/comparable/class_methods.rb
3
4
  - lib/sinclair/exception.rb
4
5
  - lib/sinclair/matchers/add_method.rb
@@ -6,5 +7,4 @@ ignore:
6
7
  - lib/sinclair/matchers/base.rb
7
8
  - lib/sinclair/matchers/change_method_on.rb
8
9
  - lib/sinclair/matchers/method_to.rb
9
- - lib/sinclair/method_definition/parameter_helper.rb
10
10
  - lib/sinclair/version.rb
data/config/yardstick.yml CHANGED
@@ -29,6 +29,7 @@ rules:
29
29
  - Sinclair::Matchers#add_class_method
30
30
  - Sinclair::Matchers#change_method
31
31
  - Sinclair::Matchers#change_class_method
32
+ - Sinclair::Model.for
32
33
  ReturnTag:
33
34
  enabled: true
34
35
  exclude:
@@ -63,6 +64,7 @@ rules:
63
64
  - Sinclair::MethodDefinition::ParameterBuilder#initialize
64
65
  - Sinclair::MethodDefinition::ParameterHelper#initialize
65
66
  - Sinclair::MethodDefinition::StringDefinition#initialize
67
+ - Sinclair::Model::Builder#initialize
66
68
  - Sinclair::Options#initialize
67
69
  - Sinclair::Options::Builder#initialize
68
70
  Summary::Length:
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @author darthjee
5
+ #
6
+ # Extension to core class Object
7
+ class Object
8
+ # rubocop:disable Naming/PredicateName
9
+
10
+ # @api public
11
+ # Checks if an object is an instance of any of the given classes
12
+ #
13
+ # @param classes [Array<Class>] classes to be checked against object
14
+ #
15
+ # @example
16
+ # object = [1, 2, 3]
17
+ #
18
+ # object.is_any?(Hash, Class) # returns false
19
+ # object.is_any?(Hash, Array) # returns true
20
+ #
21
+ # @return [TrueClass,FalseClass]
22
+ def is_any?(*classes)
23
+ classes.any?(method(:is_a?))
24
+ end
25
+ # rubocop:enable Naming/PredicateName
26
+ end
@@ -45,6 +45,7 @@ class Sinclair
45
45
 
46
46
  private
47
47
 
48
+ delegate :value_string, to: Stringifier
48
49
  attr_reader :parameters_list, :named
49
50
  alias named? named
50
51
 
@@ -114,11 +115,29 @@ class Sinclair
114
115
  #
115
116
  # @return [Array<String>]
116
117
  def defaults_strings
117
- joinner = named? ? ': ' : ' = '
118
- defaults.map do |key, value|
119
- "#{key}#{joinner}#{value}"
118
+ defaults.map do |parameter, value|
119
+ default_string(parameter, value)
120
120
  end
121
121
  end
122
+
123
+ # Returns the string for one default parameter
124
+ #
125
+ # @param parameter [Symbol] name of the parameter
126
+ # @param value [Object] default value
127
+ #
128
+ # @return [String]
129
+ def default_string(parameter, value)
130
+ "#{parameter}#{joinner}#{value_string(value)}"
131
+ end
132
+
133
+ # Returns the string used when joining a parameter with it's default value
134
+ #
135
+ # @see #named?
136
+ #
137
+ # @return [String]
138
+ def joinner
139
+ @joinner ||= named? ? ': ' : ' = '
140
+ end
122
141
  end
123
142
  end
124
143
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sinclair/core_ext/object'
4
+
5
+ class Sinclair
6
+ class MethodDefinition
7
+ # @api private
8
+ # @author darthjee
9
+ #
10
+ # Stringgify a value for {StringDefinition}
11
+ class Stringifier
12
+ # Convert a value to a string format
13
+ #
14
+ # The returned string can be evaluated as code, returning the
15
+ # original value
16
+ #
17
+ # @param value [Object] object to be converted
18
+ #
19
+ # @return [String]
20
+ def self.value_string(value)
21
+ return 'nil' if value.nil?
22
+ return ":#{value}" if value.is_a?(Symbol)
23
+
24
+ return value.to_s if value.is_any?(Class, Hash, Array)
25
+
26
+ value.to_json
27
+ end
28
+ end
29
+ end
30
+ end
@@ -14,6 +14,7 @@ class Sinclair
14
14
  autoload :StringDefinition, 'sinclair/method_definition/string_definition'
15
15
  autoload :ParameterBuilder, 'sinclair/method_definition/parameter_builder'
16
16
  autoload :ParameterHelper, 'sinclair/method_definition/parameter_helper'
17
+ autoload :Stringifier, 'sinclair/method_definition/stringifier'
17
18
 
18
19
  # @method name
19
20
  #
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ class Model
5
+ # @api private
6
+ # @author Darthjee
7
+ #
8
+ # Builder responsible for building methods to a new {Sinclair::Model} class
9
+ #
10
+ # The building adds readers/setters and an initializer with named parameters
11
+ class Builder < Sinclair
12
+ # @overload initialize(klass, *attributes, writter: true, comparable: true)
13
+ # @param klass [Class<Sinclair::Model>] the new class to receive the methods
14
+ # @param attributes [Array<Symbol>] attributes to be added in both the
15
+ # initialization and adding the methos to the model
16
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
17
+ # method should be added
18
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
19
+ # by the fields
20
+ # @overload initialize(klass, *attributes, defaults, writter: true, comparable: true)
21
+ # @param klass [Class<Sinclair::Model>] the new class to receive the methods
22
+ # @param attributes [Array<Symbol>] attributes to be added in both the
23
+ # initialization and adding the methos to the model
24
+ # @param defaults [Hash] attributes to be added with a default value in the initializer
25
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
26
+ # method should be added
27
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
28
+ # by the fields
29
+ def initialize(klass, *attributes, writter: true, comparable: true)
30
+ super(klass)
31
+ @attributes = attributes.flatten
32
+ @writter = writter
33
+ @comparable = comparable
34
+
35
+ add_methods
36
+ change_equals
37
+ change_initializer
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :attributes, :writter, :comparable
43
+ alias writter? writter
44
+ alias comparable? comparable
45
+
46
+ # @!method attributes
47
+ # @api private
48
+ # @private
49
+ #
50
+ # Attributes to be added in the class
51
+ #
52
+ # Attributes without default values are symbols
53
+ # while attributes with defaults values are defined in a Hash
54
+ #
55
+ # @return [Array<Symbol,Hash>]
56
+
57
+ # @!method writter
58
+ # @api private
59
+ # @private
60
+ #
61
+ # Flag if writter methods (setter) should be added or not
62
+ #
63
+ # @return [TrueClass,FalseClass]
64
+
65
+ # @!method comparable
66
+ # @api private
67
+ # @private
68
+ #
69
+ # flag to make the class {Comparable} by the fields
70
+ #
71
+ # @return [TrueClass,FalseClass]
72
+
73
+ # @!method writter?
74
+ # @api private
75
+ # @private
76
+ #
77
+ # Flag if writter methods (setter) should be added or not
78
+ #
79
+ # @return [TrueClass,FalseClass]
80
+
81
+ # @!method comparable?
82
+ # @api private
83
+ # @private
84
+ #
85
+ # flag to make the class {Comparable} by the fields
86
+ #
87
+ # @return [TrueClass,FalseClass]
88
+
89
+ # @private
90
+ # Adds readers and setters
91
+ #
92
+ # Readers are always added, while setters depends on the flag {#writter?}
93
+ #
94
+ # @return [Array<MethodDefinition>]
95
+ def add_methods
96
+ call = writter? ? :attr_accessor : :attr_reader
97
+
98
+ add_method(call, *attributes_names, type: :call)
99
+ end
100
+
101
+ # @private
102
+ # Change the method +==+
103
+ #
104
+ # The change happens using {Sinclair::Comparable}
105
+ # and adding all the fields to be included in the comparisom
106
+ #
107
+ # @return [Array<MethodDefinition>]
108
+ def change_equals
109
+ return unless comparable?
110
+
111
+ add_method(:include, Comparable, type: :call)
112
+ add_method(:comparable_by, *attributes_names, type: :call)
113
+ end
114
+
115
+ # @private
116
+ #
117
+ # Changes the initializer to accept the parameters
118
+ #
119
+ # @return [Array<MethodDefinition>]
120
+ def change_initializer
121
+ code = attributes_names.map do |attr|
122
+ "@#{attr} = #{attr}"
123
+ end.join("\n")
124
+
125
+ add_method(:initialize, code, named_parameters: attributes)
126
+ end
127
+
128
+ # @private
129
+ # Returns the list of attributes
130
+ #
131
+ # This is used when defining the readers / setters
132
+ #
133
+ # @return [Array<Symbol>]
134
+ def attributes_names
135
+ @attributes_names ||= attributes.map do |attr|
136
+ attr.try(:keys) || attr.to_s
137
+ end.flatten
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ # @api public
5
+ # @author Darthjee
6
+ #
7
+ # Basic model to be used when defining new classes quickly
8
+ class Model
9
+ autoload :Builder, 'sinclair/model/builder'
10
+
11
+ class << self
12
+ # Returns a new class that inherits from model
13
+ #
14
+ # @overload for(*attributes, writter: true, comparable: true)
15
+ # @param attributes [Array<Symbol>] attributes to be added in both the
16
+ # initialization and adding the methos to the model
17
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
18
+ # method should be added
19
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
20
+ # by the fields
21
+ #
22
+ # @example A model with readers
23
+ # class Car < Sinclair::Model.for(:brand, :model, writter: false)
24
+ # end
25
+ #
26
+ # car = Car.new(brand: :ford, model: :T)
27
+ #
28
+ # car.brand # returns :ford
29
+ # car.model # returns :T
30
+ #
31
+ # @overload for(*attributes, defaults, writter: true, comparable: true)
32
+ # @param attributes [Array<Symbol>] attributes to be added in both the
33
+ # initialization and adding the methos to the model
34
+ # @param defaults [Hash] attributes to be added with a default value in the initializer
35
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
36
+ # method should be added
37
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
38
+ # by the fields
39
+ #
40
+ # @example A model with writters
41
+ # class Job < Sinclair::Model.for({ state: :starting }, writter: true)
42
+ # end
43
+ #
44
+ # job = Job.new
45
+ #
46
+ # job.state # returns :starting
47
+ # job.state = :done
48
+ # job.state # returns :done
49
+ #
50
+ # @return [Class<Model>] a new class with the chosen attributes
51
+ def for(*attributes, **options)
52
+ Class.new(self) do |klass|
53
+ Builder.new(klass, *attributes, **options).build
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.12.0'
4
+ VERSION = '1.13.0'
5
5
  end
data/lib/sinclair.rb CHANGED
@@ -96,6 +96,7 @@ class Sinclair
96
96
  autoload :MethodBuilder, 'sinclair/method_builder'
97
97
  autoload :MethodDefinition, 'sinclair/method_definition'
98
98
  autoload :MethodDefinitions, 'sinclair/method_definitions'
99
+ autoload :Model, 'sinclair/model'
99
100
  autoload :Options, 'sinclair/options'
100
101
 
101
102
  include OptionsParser
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Model do
6
+ describe 'readme' do
7
+ it 'Simple usage' do
8
+ human1 = Human.new(name: 'John Doe', age: 22)
9
+ human2 = Human.new(name: 'John Doe', age: 22)
10
+
11
+ expect(human1.name).to eq('John Doe')
12
+ expect(human1.age).to eq(22)
13
+ expect(human1.gender).to eq(:undefined)
14
+ expect(human1 == human2).to eq(true)
15
+ end
16
+
17
+ it 'Without comparable' do
18
+ tv1 = Tv.new(model: 'Sans Sunga Xt')
19
+ tv2 = Tv.new(model: 'Sans Sunga Xt')
20
+
21
+ expect(tv1 == tv2).to eq(false)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Object do
4
+ describe 'yard' do
5
+ describe '#is_any?' do
6
+ context 'when none match' do
7
+ it do
8
+ object = [1, 2, 3]
9
+
10
+ expect(object.is_any?(Hash, Class)).to eq(false)
11
+ expect(object.is_any?(Hash, Array)).to eq(true)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'yard Sinclair::Model#for' do
6
+ it 'Creating a Simple model' do
7
+ car = Car.new(brand: :ford, model: :T)
8
+
9
+ expect(car.brand).to eq(:ford)
10
+ expect(car.model).to eq(:T)
11
+ end
12
+
13
+ it 'Creating a model with default values and writter' do
14
+ job = Job.new
15
+
16
+ expect(job.state).to eq(:starting)
17
+ job.state = :done
18
+ expect(job.state).to eq(:done)
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Object do
6
+ describe '#is_any?' do
7
+ subject(:object) { 1 }
8
+
9
+ it do
10
+ expect(object).to respond_to(:is_any?)
11
+ end
12
+
13
+ context 'when no argument is passed' do
14
+ it do
15
+ expect(object).not_to be_is_any
16
+ end
17
+ end
18
+
19
+ context 'when passing the correct class as argument' do
20
+ it do
21
+ expect(object).to be_is_any(object.class)
22
+ end
23
+
24
+ context 'when passing any other class' do
25
+ it do
26
+ expect(object).to be_is_any(Symbol, object.class)
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'when passing the wrong class' do
32
+ it do
33
+ expect(object).not_to be_is_any(Symbol)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::MethodDefinition::ParameterHelper do
6
+ describe '.parameters_from' do
7
+ context 'when parameters are not named' do
8
+ context 'when there are no defaults' do
9
+ it 'returns a list of parameters' do
10
+ expect(described_class.parameters_from(%i[a b]))
11
+ .to eq(%w[a b])
12
+ end
13
+ end
14
+
15
+ context 'when there are defaults' do
16
+ let(:parameters) do
17
+ [{ a: 10, b: 'word', c: true, d: false, e: nil, f: :symbol }]
18
+ end
19
+
20
+ it 'returns a list of parameters' do
21
+ expect(described_class.parameters_from(parameters))
22
+ .to eq(['a = 10', 'b = "word"', 'c = true', 'd = false', 'e = nil', 'f = :symbol'])
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'when parameters are named' do
28
+ context 'when there are no defaults' do
29
+ it 'returns a list of parameters' do
30
+ expect(described_class.parameters_from(%i[a b], named: true))
31
+ .to eq(%w[a: b:])
32
+ end
33
+ end
34
+
35
+ context 'when there are defaults' do
36
+ let(:parameters) do
37
+ [{ a: 10, b: 'word', c: true, d: false, e: nil, f: :symbol }]
38
+ end
39
+
40
+ it 'returns a list of parameters' do
41
+ expect(described_class.parameters_from(parameters, named: true))
42
+ .to eq(['a: 10', 'b: "word"', 'c: true', 'd: false', 'e: nil', 'f: :symbol'])
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::MethodDefinition::Stringifier do
6
+ describe '.value_string' do
7
+ context 'when value is nil' do
8
+ it 'returns string representing nil' do
9
+ expect(described_class.value_string(nil)).to eq('nil')
10
+ end
11
+ end
12
+
13
+ context 'when value is a symbol' do
14
+ it 'returns string representing a symbol' do
15
+ expect(described_class.value_string(:symbol)).to eq(':symbol')
16
+ end
17
+ end
18
+
19
+ context 'when value is a string' do
20
+ it 'returns string representing a string' do
21
+ expect(described_class.value_string('string')).to eq('"string"')
22
+ end
23
+ end
24
+
25
+ context 'when value is a number' do
26
+ it 'returns string representing a number' do
27
+ expect(described_class.value_string(10)).to eq('10')
28
+ end
29
+ end
30
+
31
+ context 'when value is a float' do
32
+ it 'returns string representing a float' do
33
+ expect(described_class.value_string(1.20)).to eq('1.2')
34
+ end
35
+ end
36
+
37
+ context 'when value is a true' do
38
+ it 'returns string representing a true' do
39
+ expect(described_class.value_string(true)).to eq('true')
40
+ end
41
+ end
42
+
43
+ context 'when value is a false' do
44
+ it 'returns string representing a false' do
45
+ expect(described_class.value_string(false)).to eq('false')
46
+ end
47
+ end
48
+
49
+ context 'when value is a class' do
50
+ it 'returns string representing a class' do
51
+ expect(described_class.value_string(Sinclair::Model)).to eq('Sinclair::Model')
52
+ end
53
+ end
54
+
55
+ context 'when value is a hash' do
56
+ it 'returns string representing a Hash' do
57
+ expect(described_class.value_string({ a: 10, 'b' => 'value' }))
58
+ .to eq('{:a=>10, "b"=>"value"}')
59
+ end
60
+ end
61
+
62
+ context 'when value is an Array' do
63
+ it 'returns string representing a Array' do
64
+ expect(described_class.value_string([:a, 10, 'b', true, nil]))
65
+ .to eq('[:a, 10, "b", true, nil]')
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Model do
6
+ describe '.with_attributes' do
7
+ subject(:model) { klass.new(name: name) }
8
+
9
+ let(:name) { SecureRandom.hex(10) }
10
+ let(:attributes) { %i[name] }
11
+
12
+ context 'when the call happens with no options' do
13
+ subject(:klass) { described_class.for(*attributes) }
14
+
15
+ it 'Returns a new class' do
16
+ expect(klass.superclass)
17
+ .to eq(described_class)
18
+ end
19
+
20
+ it 'returns a class with getter' do
21
+ expect(klass.instance_method(:name))
22
+ .to be_a(UnboundMethod)
23
+ end
24
+
25
+ it 'returns a class with setter' do
26
+ expect(klass.instance_method(:name=))
27
+ .to be_a(UnboundMethod)
28
+ end
29
+
30
+ it 'returns a new class with a comparable that finds matches' do
31
+ expect(model).to eq(klass.new(name: name))
32
+ end
33
+
34
+ it 'returns a new class with a comparable that find misses' do
35
+ expect(model).not_to eq(klass.new(name: SecureRandom.hex(10)))
36
+ end
37
+
38
+ context 'when reader is called' do
39
+ it do
40
+ expect(model.name).to eq(name)
41
+ end
42
+ end
43
+
44
+ context 'when setter is called' do
45
+ let(:name) { SecureRandom.hex(10) }
46
+ let(:model) { klass.new(name: nil) }
47
+
48
+ it do
49
+ expect { model.name = name }
50
+ .to change(model, :name)
51
+ .from(nil)
52
+ .to(name)
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when the call happens with comparable false' do
58
+ subject(:klass) { described_class.for(*attributes, **options) }
59
+
60
+ let(:options) { { comparable: false } }
61
+
62
+ it 'returns a new class without comparable' do
63
+ expect(model).not_to eq(klass.new(name: name))
64
+ end
65
+ end
66
+
67
+ context 'when the call happens with reader options' do
68
+ subject(:klass) { described_class.for(*attributes, **options) }
69
+
70
+ let(:options) { { writter: false } }
71
+
72
+ it 'Returns a new class' do
73
+ expect(klass.superclass)
74
+ .to eq(described_class)
75
+ end
76
+
77
+ it 'returns a class with getter' do
78
+ expect(klass.instance_method(:name))
79
+ .to be_a(UnboundMethod)
80
+ end
81
+
82
+ it 'returns a class without setter' do
83
+ expect { klass.instance_method(:name=) }
84
+ .to raise_error(NameError)
85
+ end
86
+
87
+ context 'when reader is called' do
88
+ it do
89
+ expect(model.name).to eq(name)
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'when the call happens with defaults' do
95
+ subject(:klass) do
96
+ described_class.for({ name: 'John Doe' }, **{})
97
+ end
98
+
99
+ it 'Returns a new class' do
100
+ expect(klass.superclass)
101
+ .to eq(described_class)
102
+ end
103
+
104
+ it 'returns a class with getter' do
105
+ expect(klass.instance_method(:name))
106
+ .to be_a(UnboundMethod)
107
+ end
108
+
109
+ it 'returns a class with setter' do
110
+ expect(klass.instance_method(:name=))
111
+ .to be_a(UnboundMethod)
112
+ end
113
+
114
+ context 'when reader is called' do
115
+ subject(:model) { klass.new }
116
+
117
+ let(:name) { SecureRandom.hex(10) }
118
+
119
+ it 'returns the dfault value' do
120
+ expect(model.name).to eq('John Doe')
121
+ end
122
+ end
123
+
124
+ context 'when setter is called' do
125
+ subject(:model) { klass.new }
126
+
127
+ let(:name) { SecureRandom.hex(10) }
128
+
129
+ it do
130
+ expect { model.name = name }
131
+ .to change(model, :name)
132
+ .from('John Doe')
133
+ .to(name)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: false
2
+
3
+ class Car < Sinclair::Model.for(:brand, :model, writter: false)
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Human < Sinclair::Model.for(:name, :age, { gender: :undefined }, **{})
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: false
2
+
3
+ class Job < Sinclair::Model.for({ state: :starting }, writter: true)
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tv < Sinclair::Model.for(:model, writter: false, comparable: false)
4
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinclair
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DarthJee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-14 00:00:00.000000000 Z
11
+ date: 2023-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -280,6 +280,7 @@ files:
280
280
  - lib/sinclair/config_class.rb
281
281
  - lib/sinclair/config_factory.rb
282
282
  - lib/sinclair/configurable.rb
283
+ - lib/sinclair/core_ext/object.rb
283
284
  - lib/sinclair/env_settable.rb
284
285
  - lib/sinclair/env_settable/builder.rb
285
286
  - lib/sinclair/equals_checker.rb
@@ -311,7 +312,10 @@ files:
311
312
  - lib/sinclair/method_definition/parameter_builder.rb
312
313
  - lib/sinclair/method_definition/parameter_helper.rb
313
314
  - lib/sinclair/method_definition/string_definition.rb
315
+ - lib/sinclair/method_definition/stringifier.rb
314
316
  - lib/sinclair/method_definitions.rb
317
+ - lib/sinclair/model.rb
318
+ - lib/sinclair/model/builder.rb
315
319
  - lib/sinclair/options.rb
316
320
  - lib/sinclair/options/builder.rb
317
321
  - lib/sinclair/options/class_methods.rb
@@ -325,6 +329,7 @@ files:
325
329
  - spec/integration/readme/sinclair/configurable_spec.rb
326
330
  - spec/integration/readme/sinclair/env_settable_spec.rb
327
331
  - spec/integration/readme/sinclair/matchers_spec.rb
332
+ - spec/integration/readme/sinclair/model_spec.rb
328
333
  - spec/integration/readme/sinclair/options_spec.rb
329
334
  - spec/integration/readme/sinclair/types_of_definition_spec.rb
330
335
  - spec/integration/readme/sinclair_spec.rb
@@ -337,6 +342,7 @@ files:
337
342
  - spec/integration/yard/sinclair/config_factory_spec.rb
338
343
  - spec/integration/yard/sinclair/config_spec.rb
339
344
  - spec/integration/yard/sinclair/configurable_spec.rb
345
+ - spec/integration/yard/sinclair/core_ext/object_spec.rb
340
346
  - spec/integration/yard/sinclair/env_settable_spec.rb
341
347
  - spec/integration/yard/sinclair/equals_checker_spec.rb
342
348
  - spec/integration/yard/sinclair/eval_and_add_method_spec.rb
@@ -347,6 +353,7 @@ files:
347
353
  - spec/integration/yard/sinclair/matchers/add_instance_method_to_spec.rb
348
354
  - spec/integration/yard/sinclair/matchers/change_class_method_spec.rb
349
355
  - spec/integration/yard/sinclair/matchers/change_instance_method_spec.rb
356
+ - spec/integration/yard/sinclair/model_spec.rb
350
357
  - spec/integration/yard/sinclair/options_parser_spec.rb
351
358
  - spec/integration/yard/sinclair/options_spec.rb
352
359
  - spec/integration/yard/sinclair_spec.rb
@@ -357,6 +364,7 @@ files:
357
364
  - spec/lib/sinclair/config_factory_spec.rb
358
365
  - spec/lib/sinclair/config_spec.rb
359
366
  - spec/lib/sinclair/configurable_spec.rb
367
+ - spec/lib/sinclair/core_ext/object_spec.rb
360
368
  - spec/lib/sinclair/env_settable/builder_spec.rb
361
369
  - spec/lib/sinclair/env_settable_spec.rb
362
370
  - spec/lib/sinclair/equals_checker_spec.rb
@@ -380,9 +388,12 @@ files:
380
388
  - spec/lib/sinclair/method_definition/block_helper_spec.rb
381
389
  - spec/lib/sinclair/method_definition/call_definition_spec.rb
382
390
  - spec/lib/sinclair/method_definition/parameter_builder_spec.rb
391
+ - spec/lib/sinclair/method_definition/parameter_helper_spec.rb
383
392
  - spec/lib/sinclair/method_definition/string_definition_spec.rb
393
+ - spec/lib/sinclair/method_definition/stringifier_spec.rb
384
394
  - spec/lib/sinclair/method_definition_spec.rb
385
395
  - spec/lib/sinclair/method_definitions_spec.rb
396
+ - spec/lib/sinclair/model_spec.rb
386
397
  - spec/lib/sinclair/options/builder_spec.rb
387
398
  - spec/lib/sinclair/options/class_methods_spec.rb
388
399
  - spec/lib/sinclair/options_parser_spec.rb
@@ -393,6 +404,7 @@ files:
393
404
  - spec/support/models/app_client.rb
394
405
  - spec/support/models/app_config.rb
395
406
  - spec/support/models/builder_options.rb
407
+ - spec/support/models/car.rb
396
408
  - spec/support/models/client.rb
397
409
  - spec/support/models/connection_options.rb
398
410
  - spec/support/models/default_value.rb
@@ -407,7 +419,9 @@ files:
407
419
  - spec/support/models/host_config.rb
408
420
  - spec/support/models/http_json_model.rb
409
421
  - spec/support/models/http_person.rb
422
+ - spec/support/models/human.rb
410
423
  - spec/support/models/initial_valuer.rb
424
+ - spec/support/models/job.rb
411
425
  - spec/support/models/login_config.rb
412
426
  - spec/support/models/login_configurable.rb
413
427
  - spec/support/models/my_app_client.rb
@@ -425,6 +439,7 @@ files:
425
439
  - spec/support/models/server.rb
426
440
  - spec/support/models/server_config.rb
427
441
  - spec/support/models/service_client.rb
442
+ - spec/support/models/tv.rb
428
443
  - spec/support/models/validator_builder.rb
429
444
  - spec/support/sample_model.rb
430
445
  - spec/support/shared_examples/attribute_accessor.rb