sinclair 1.12.1 → 1.14.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: 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: []