sinclair 1.12.1 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b14d0d24d28075129d870b9f2b93c306e894407a70878d7950e0c73e7f747dbb
4
- data.tar.gz: 5a3d836d3b8eb5dc299dd17836e50f387fe3273820e91ef95581aac25348407d
3
+ metadata.gz: 6ee09cd280144bc873d89c0272856bf716e0a20c2ca5d3f7fe8bf11ac972c859
4
+ data.tar.gz: c5107aa15ffab29f4dd14b45efd0387913c60064ad62a58c4ec85adb09d91c9c
5
5
  SHA512:
6
- metadata.gz: c6bbf090685049aaa1936e632ed420060ccead6071bb9864de3b5e26f16ad68431b6d01de24442f4ac4ce87792158a5def414680fe9d6b941d4031b766bd386e
7
- data.tar.gz: ef28a8f5b9f5b9e9e12cd36c558fe2bb14fededbea91df46cda1b2d8570d0fec22809dc3e36f4af61844da370ea659463df03562232883121d0ebc7f40a63e81
6
+ metadata.gz: 38994db2d8a69ef1b9f3827a84bcb53a0bd18e2073a4840b004a89ac00a0fe0f5d9a8a69ce231b9d6c5f2cfc51b3a96c5ee898c848ce7ba802eac1d8556a058b
7
+ data.tar.gz: 4812c5a5793de217eb0cdd895c8cc94ac698af119c60fded29ea6929bddf0240b9dbcdba237dba7c1f060a3c3b8a3a173d2c7fef0509f6181d738ca0c7f0ef34
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.1](https://github.com/darthjee/sinclair/tree/1.12.1)
16
+ Current Release: [1.14.0](https://github.com/darthjee/sinclair/tree/1.14.0)
17
17
 
18
- [Next release](https://github.com/darthjee/sinclair/compare/1.12.1...master)
18
+ [Next release](https://github.com/darthjee/sinclair/compare/1.14.0...master)
19
19
 
20
20
  Yard Documentation
21
21
  -------------------
22
- [https://www.rubydoc.info/gems/sinclair/1.12.1](https://www.rubydoc.info/gems/sinclair/1.12.1)
22
+ [https://www.rubydoc.info/gems/sinclair/1.14.0](https://www.rubydoc.info/gems/sinclair/1.14.0)
23
23
 
24
24
  Installation
25
25
  ---------------
@@ -616,6 +616,45 @@ 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
631
+ initialize_with :name, :age, { gender: :undefined }, **{}
632
+ end
633
+
634
+ human1 = Human.new(name: 'John Doe', age: 22)
635
+ human2 = Human.new(name: 'John Doe', age: 22)
636
+
637
+ human1.name # returns 'John Doe'
638
+ human1.age # returns 22
639
+ human1.gender # returns :undefined
640
+ human1 == human2 # returns true
641
+ ```
642
+ </details>
643
+
644
+ <details>
645
+ <summary>Example with options</summary>
646
+
647
+ ```ruby
648
+ class Tv < Sinclair::Model.for(:model, writter: false, comparable: false)
649
+ end
650
+
651
+ tv1 = Tv.new(model: 'Sans Sunga Xt')
652
+ tv2 = Tv.new(model: 'Sans Sunga Xt')
653
+
654
+ tv1 == tv2 # returns false
655
+ ```
656
+ </details>
657
+
619
658
  RSspec matcher
620
659
  ---------------
621
660
 
@@ -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
data/config/yardstick.yml CHANGED
@@ -29,6 +29,8 @@ 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
33
+ - Sinclair::Model.initialize_with
32
34
  ReturnTag:
33
35
  enabled: true
34
36
  exclude:
@@ -63,6 +65,7 @@ rules:
63
65
  - Sinclair::MethodDefinition::ParameterBuilder#initialize
64
66
  - Sinclair::MethodDefinition::ParameterHelper#initialize
65
67
  - Sinclair::MethodDefinition::StringDefinition#initialize
68
+ - Sinclair::Model::Builder#initialize
66
69
  - Sinclair::Options#initialize
67
70
  - Sinclair::Options::Builder#initialize
68
71
  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.to_json}"
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,107 @@
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
+ # @deprecated Use {.initialize_with} instead
15
+ #
16
+ # @overload for(*attributes, writter: true, comparable: true)
17
+ # @param attributes [Array<Symbol>] attributes to be added in both the
18
+ # initialization and adding the methos to the model
19
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
20
+ # method should be added
21
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
22
+ # by the fields
23
+ #
24
+ # @example A model with readers
25
+ # class Car < Sinclair::Model.for(:brand, :model, writter: false)
26
+ # end
27
+ #
28
+ # car = Car.new(brand: :ford, model: :T)
29
+ #
30
+ # car.brand # returns :ford
31
+ # car.model # returns :T
32
+ #
33
+ # @overload for(*attributes, defaults, writter: true, comparable: true)
34
+ # @param attributes [Array<Symbol>] attributes to be added in both the
35
+ # initialization and adding the methos to the model
36
+ # @param defaults [Hash] attributes to be added with a default value in the initializer
37
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
38
+ # method should be added
39
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
40
+ # by the fields
41
+ #
42
+ # @example A model with writters
43
+ # class Job < Sinclair::Model.for({ state: :starting }, writter: true)
44
+ # end
45
+ #
46
+ # job = Job.new
47
+ #
48
+ # job.state # returns :starting
49
+ # job.state = :done
50
+ # job.state # returns :done
51
+ #
52
+ # @return [Class<Model>] a new class with the chosen attributes
53
+ def for(*attributes, **options)
54
+ Class.new(self) do |klass|
55
+ Builder.new(klass, *attributes, **options).build
56
+ end
57
+ end
58
+
59
+ # Adds methods needed for the model
60
+ #
61
+ # The readers/writters, +==+ and initializer are added
62
+ #
63
+ # @overload initialize_with(*attributes, writter: true, comparable: true)
64
+ # @param attributes [Array<Symbol>] attributes to be added in both the
65
+ # initialization and adding the methos to the model
66
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
67
+ # method should be added
68
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
69
+ # by the fields
70
+ #
71
+ # @example A model with readers
72
+ # class Car < Sinclair::Model
73
+ # initialize_with(:brand, :model, writter: false)
74
+ # end
75
+ #
76
+ # car = Car.new(brand: :ford, model: :T)
77
+ #
78
+ # car.brand # returns :ford
79
+ # car.model # returns :T
80
+ #
81
+ # @overload initialize_with(*attributes, defaults, writter: true, comparable: true)
82
+ # @param attributes [Array<Symbol>] attributes to be added in both the
83
+ # initialization and adding the methos to the model
84
+ # @param defaults [Hash] attributes to be added with a default value in the initializer
85
+ # @param writter [TrueClass,FalseClass] flag informing if the writter/setter
86
+ # method should be added
87
+ # @param comparable [TrueClass,FalseClass] flag to make the class {Comparable}
88
+ # by the fields
89
+ #
90
+ # @example A model with writters
91
+ # class Job < Sinclair::Model
92
+ # initialize_with({ state: :starting }, writter: true)
93
+ # end
94
+ #
95
+ # job = Job.new
96
+ #
97
+ # job.state # returns :starting
98
+ # job.state = :done
99
+ # job.state # returns :done
100
+ #
101
+ # @return [Array<MethodDefinition>]
102
+ def initialize_with(*attributes, **options)
103
+ Builder.new(self, *attributes, **options).build
104
+ end
105
+ end
106
+ end
107
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.12.1'
4
+ VERSION = '1.14.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
@@ -14,12 +14,12 @@ describe Sinclair::MethodDefinition::ParameterHelper do
14
14
 
15
15
  context 'when there are defaults' do
16
16
  let(:parameters) do
17
- [{ a: 10, b: 'word', c: true, d: false }]
17
+ [{ a: 10, b: 'word', c: true, d: false, e: nil, f: :symbol }]
18
18
  end
19
19
 
20
20
  it 'returns a list of parameters' do
21
21
  expect(described_class.parameters_from(parameters))
22
- .to eq(['a = 10', 'b = "word"', 'c = true', 'd = false'])
22
+ .to eq(['a = 10', 'b = "word"', 'c = true', 'd = false', 'e = nil', 'f = :symbol'])
23
23
  end
24
24
  end
25
25
  end
@@ -34,12 +34,12 @@ describe Sinclair::MethodDefinition::ParameterHelper do
34
34
 
35
35
  context 'when there are defaults' do
36
36
  let(:parameters) do
37
- [{ a: 10, b: 'word', c: true, d: false }]
37
+ [{ a: 10, b: 'word', c: true, d: false, e: nil, f: :symbol }]
38
38
  end
39
39
 
40
40
  it 'returns a list of parameters' do
41
41
  expect(described_class.parameters_from(parameters, named: true))
42
- .to eq(['a: 10', 'b: "word"', 'c: true', 'd: false'])
42
+ .to eq(['a: 10', 'b: "word"', 'c: true', 'd: false', 'e: nil', 'f: :symbol'])
43
43
  end
44
44
  end
45
45
  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,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Model do
6
+ subject(:model) { klass.new(name: name) }
7
+
8
+ let(:name) { SecureRandom.hex(10) }
9
+ let(:attributes) { %i[name] }
10
+ let(:options) { {} }
11
+
12
+ describe '.for' do
13
+ subject(:klass) { described_class.for(*attributes, **options) }
14
+
15
+ it_behaves_like 'sinclair model building'
16
+ end
17
+
18
+ describe '.initialize_with' do
19
+ subject(:klass) { Class.new(described_class) }
20
+
21
+ context 'when no options are given' do
22
+ it do
23
+ expect { klass.initialize_with(*attributes, **options) }
24
+ .to add_method(:name).to(klass)
25
+ end
26
+
27
+ it do
28
+ expect { klass.initialize_with(*attributes, **options) }
29
+ .to add_method(:name=).to(klass)
30
+ end
31
+
32
+ it do
33
+ expect { klass.initialize_with(*attributes, **options) }
34
+ .to change_method(:==).on(klass)
35
+ end
36
+ end
37
+
38
+ context 'when writter and comparable are not enabled' do
39
+ let(:options) { { writter: false, comparable: false } }
40
+
41
+ it do
42
+ expect { klass.initialize_with(*attributes, **options) }
43
+ .to add_method(:name).to(klass)
44
+ end
45
+
46
+ it do
47
+ expect { klass.initialize_with(*attributes, **options) }
48
+ .not_to add_method(:name=).to(klass)
49
+ end
50
+
51
+ it do
52
+ expect { klass.initialize_with(*attributes, **options) }
53
+ .not_to change_method(:==).on(klass)
54
+ end
55
+ end
56
+
57
+ context 'when the build is done' do
58
+ before do
59
+ klass.initialize_with(*attributes, **options)
60
+ end
61
+
62
+ it_behaves_like 'sinclair model building'
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: false
2
+
3
+ class Car < Sinclair::Model
4
+ initialize_with(:brand, :model, writter: false)
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Human < Sinclair::Model
4
+ initialize_with :name, :age, { gender: :undefined }, **{}
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: false
2
+
3
+ class Job < Sinclair::Model
4
+ initialize_with({ state: :starting }, writter: true)
5
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Tv < Sinclair::Model.for(:model, writter: false, comparable: false)
4
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples 'sinclair model building' do
4
+ context 'when the call happens with no options' do
5
+ it 'Returns a new class' do
6
+ expect(klass.superclass)
7
+ .to eq(described_class)
8
+ end
9
+
10
+ it 'returns a class with getter' do
11
+ expect(klass.instance_method(:name))
12
+ .to be_a(UnboundMethod)
13
+ end
14
+
15
+ it 'returns a class with setter' do
16
+ expect(klass.instance_method(:name=))
17
+ .to be_a(UnboundMethod)
18
+ end
19
+
20
+ it 'returns a new class with a comparable that finds matches' do
21
+ expect(model).to eq(klass.new(name: name))
22
+ end
23
+
24
+ it 'returns a new class with a comparable that find misses' do
25
+ expect(model).not_to eq(klass.new(name: SecureRandom.hex(10)))
26
+ end
27
+
28
+ context 'when reader is called' do
29
+ it do
30
+ expect(model.name).to eq(name)
31
+ end
32
+ end
33
+
34
+ context 'when setter is called' do
35
+ let(:name) { SecureRandom.hex(10) }
36
+ let(:model) { klass.new(name: nil) }
37
+
38
+ it do
39
+ expect { model.name = name }
40
+ .to change(model, :name)
41
+ .from(nil)
42
+ .to(name)
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'when the call happens with comparable false' do
48
+ let(:options) { { comparable: false } }
49
+
50
+ it 'returns a new class without comparable' do
51
+ expect(model).not_to eq(klass.new(name: name))
52
+ end
53
+ end
54
+
55
+ context 'when the call happens with reader options' do
56
+ let(:options) { { writter: false } }
57
+
58
+ it 'Returns a new class' do
59
+ expect(klass.superclass)
60
+ .to eq(described_class)
61
+ end
62
+
63
+ it 'returns a class with getter' do
64
+ expect(klass.instance_method(:name))
65
+ .to be_a(UnboundMethod)
66
+ end
67
+
68
+ it 'returns a class without setter' do
69
+ expect { klass.instance_method(:name=) }
70
+ .to raise_error(NameError)
71
+ end
72
+
73
+ context 'when reader is called' do
74
+ it do
75
+ expect(model.name).to eq(name)
76
+ end
77
+ end
78
+ end
79
+
80
+ context 'when the call happens with defaults' do
81
+ let(:attributes) { [{ name: 'John Doe' }] }
82
+
83
+ it 'Returns a new class' do
84
+ expect(klass.superclass)
85
+ .to eq(described_class)
86
+ end
87
+
88
+ it 'returns a class with getter' do
89
+ expect(klass.instance_method(:name))
90
+ .to be_a(UnboundMethod)
91
+ end
92
+
93
+ it 'returns a class with setter' do
94
+ expect(klass.instance_method(:name=))
95
+ .to be_a(UnboundMethod)
96
+ end
97
+
98
+ context 'when reader is called' do
99
+ subject(:model) { klass.new }
100
+
101
+ let(:name) { SecureRandom.hex(10) }
102
+
103
+ it 'returns the dfault value' do
104
+ expect(model.name).to eq('John Doe')
105
+ end
106
+ end
107
+
108
+ context 'when setter is called' do
109
+ subject(:model) { klass.new }
110
+
111
+ let(:name) { SecureRandom.hex(10) }
112
+
113
+ it do
114
+ expect { model.name = name }
115
+ .to change(model, :name)
116
+ .from('John Doe')
117
+ .to(name)
118
+ end
119
+ end
120
+ end
121
+ 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.1
4
+ version: 1.14.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-15 00:00:00.000000000 Z
11
+ date: 2023-03-16 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
@@ -382,8 +390,10 @@ files:
382
390
  - spec/lib/sinclair/method_definition/parameter_builder_spec.rb
383
391
  - spec/lib/sinclair/method_definition/parameter_helper_spec.rb
384
392
  - spec/lib/sinclair/method_definition/string_definition_spec.rb
393
+ - spec/lib/sinclair/method_definition/stringifier_spec.rb
385
394
  - spec/lib/sinclair/method_definition_spec.rb
386
395
  - spec/lib/sinclair/method_definitions_spec.rb
396
+ - spec/lib/sinclair/model_spec.rb
387
397
  - spec/lib/sinclair/options/builder_spec.rb
388
398
  - spec/lib/sinclair/options/class_methods_spec.rb
389
399
  - spec/lib/sinclair/options_parser_spec.rb
@@ -394,6 +404,7 @@ files:
394
404
  - spec/support/models/app_client.rb
395
405
  - spec/support/models/app_config.rb
396
406
  - spec/support/models/builder_options.rb
407
+ - spec/support/models/car.rb
397
408
  - spec/support/models/client.rb
398
409
  - spec/support/models/connection_options.rb
399
410
  - spec/support/models/default_value.rb
@@ -408,7 +419,9 @@ files:
408
419
  - spec/support/models/host_config.rb
409
420
  - spec/support/models/http_json_model.rb
410
421
  - spec/support/models/http_person.rb
422
+ - spec/support/models/human.rb
411
423
  - spec/support/models/initial_valuer.rb
424
+ - spec/support/models/job.rb
412
425
  - spec/support/models/login_config.rb
413
426
  - spec/support/models/login_configurable.rb
414
427
  - spec/support/models/my_app_client.rb
@@ -426,6 +439,7 @@ files:
426
439
  - spec/support/models/server.rb
427
440
  - spec/support/models/server_config.rb
428
441
  - spec/support/models/service_client.rb
442
+ - spec/support/models/tv.rb
429
443
  - spec/support/models/validator_builder.rb
430
444
  - spec/support/sample_model.rb
431
445
  - spec/support/shared_examples/attribute_accessor.rb
@@ -434,6 +448,7 @@ files:
434
448
  - spec/support/shared_examples/config_factory.rb
435
449
  - spec/support/shared_examples/env_settable.rb
436
450
  - spec/support/shared_examples/instance_method_definition.rb
451
+ - spec/support/shared_examples/model.rb
437
452
  - spec/support/shared_examples/sinclair.rb
438
453
  homepage: https://github.com/darthjee/sinclair
439
454
  licenses: []