portrayal 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eeb24e8ffff128d18963b1b9b35b542b260a2ec3b0e298064201c108a58c0c6c
4
- data.tar.gz: 36adc49da54f8a4756d08dd0f33fbff9b6b5366115082682ff9b9fd46bd26687
3
+ metadata.gz: 577a51dc874a79a5cb7aece4157c2d802005f3fa9c3daba4b807db522c7cd7ae
4
+ data.tar.gz: b30f1ea6a9438ba5b4574a68935602fce1dd0a447d15dce4227d0a67a10b2e87
5
5
  SHA512:
6
- metadata.gz: 992c3b99a75e3b0226d55cc6429072be5abac8248aab9e43903352a2aeb50b0ad29acdb3dd28993ae7ddabc46b3784440d5048afef958d1ffdae1bc9e6f4738c
7
- data.tar.gz: 4bc0a1cec3d59ae6db9e22e60504accc420e036ab197313e1c0b9f71219e3aae341acf82de1faa2f88984e6af79d19f1c4f825ad1fc5594b12db3497dcdc168c
6
+ metadata.gz: a02d197cb3c56e88afcda74a58d5d7034ef4739de707380c05b7a1a76c95e8ae1c8aa9341fde97d8efa69e6b5fcc00df429b2ada5e1b18f5dc9c2c51cc73504a
7
+ data.tar.gz: 4c6f5e4d359551e7420dd4331192f857f8a4518ab679b8052f36c6854a34a100a97bd4af98358589dcd08144cff9ddda071f6b2bd4602dc7495d2fc8467c6994
@@ -0,0 +1,24 @@
1
+ name: RSpec
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby: [ '2.4', '2.5', '2.6', '2.7' ]
15
+
16
+ name: Ruby ${{ matrix.ruby }}
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: actions/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - run: gem install bundler
23
+ - run: bundle install
24
+ - run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -1,11 +1,23 @@
1
1
  This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2
2
 
3
- ## [0.2.0] - 2019-07-03
3
+ ## Unreleased
4
4
 
5
- ### Changed
5
+ ## 0.3.1 - 2020-05-11
6
6
 
7
- * It's now possible to specify non-lambda default values, like `default: "foo". There is now also a distinction between a proc and a lambda default. Procs are `call`-ed, while lambdas or any other types are returned as-is. In the majority of cases defaults are static values, and there is no need for the performance overhead of making all defaults into anonymous functions.
7
+ * Fix the issue introduced in 0.3.0 where `==` and `eql?` were always treating rhs as another portrayal class.
8
8
 
9
- ## [0.1.0]
9
+ ## 0.3.0 - 2020-05-09
10
+
11
+ * No longer compare classes in `==`, use `eql?` for that. [[commit]](https://github.com/scottscheapflights/portrayal/commit/9c5a37e4fb91e35d23b22e208344452930452af7)
12
+ * Define a protected writer for every keyword - useful when applying changes after `dup`/`clone`. [[commit]](https://github.com/scottscheapflights/portrayal/commit/1c0fa6c6357a09760dae39165e864238d231a08e)
13
+ * Add definition of `#hash` to fix hash equality. Now `hash[object]` will match if `object` is of the same class with the same keywords and values. [[commit]](https://github.com/scottscheapflights/portrayal/commit/ba9e390ab4aea4733ba084ac273da448e313ea53)
14
+ * Make `#freeze` propagate to all keyword values. [[commit]](https://github.com/scottscheapflights/portrayal/commit/0a734411a6eac08e2355c4277e09a2a70800d032)
15
+ * Make `#dup` and `#clone` propagate to all keyword values. [[commit]](https://github.com/scottscheapflights/portrayal/commit/010632d87d81a8d5b5ea5ff27d3d209cc667b0a5)
16
+
17
+ ## 0.2.0 - 2019-07-03
18
+
19
+ * It's now possible to specify non-lambda default values, like `default: "foo"`. There is now also a distinction between a proc and a lambda default. Procs are `call`-ed, while lambdas or any other types are returned as-is. In the majority of cases defaults are static values, and there is no need for the performance overhead of making all defaults into anonymous functions. [[commit]](https://github.com/scottscheapflights/portrayal/commit/a1cc9d0fd40e413210f61b945d37b81c87280fee)
20
+
21
+ ## 0.1.0
10
22
 
11
23
  First version.
data/Gemfile.lock CHANGED
@@ -1,41 +1,41 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- portrayal (0.2.0)
4
+ portrayal (0.3.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  coderay (1.1.2)
10
10
  diff-lcs (1.3)
11
- method_source (0.9.2)
12
- pry (0.12.2)
13
- coderay (~> 1.1.0)
14
- method_source (~> 0.9.0)
15
- rake (10.5.0)
16
- rspec (3.8.0)
17
- rspec-core (~> 3.8.0)
18
- rspec-expectations (~> 3.8.0)
19
- rspec-mocks (~> 3.8.0)
20
- rspec-core (3.8.0)
21
- rspec-support (~> 3.8.0)
22
- rspec-expectations (3.8.3)
11
+ method_source (1.0.0)
12
+ pry (0.13.1)
13
+ coderay (~> 1.1)
14
+ method_source (~> 1.0)
15
+ rake (13.0.1)
16
+ rspec (3.9.0)
17
+ rspec-core (~> 3.9.0)
18
+ rspec-expectations (~> 3.9.0)
19
+ rspec-mocks (~> 3.9.0)
20
+ rspec-core (3.9.2)
21
+ rspec-support (~> 3.9.3)
22
+ rspec-expectations (3.9.2)
23
23
  diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.8.0)
25
- rspec-mocks (3.8.0)
24
+ rspec-support (~> 3.9.0)
25
+ rspec-mocks (3.9.1)
26
26
  diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.8.0)
28
- rspec-support (3.8.0)
27
+ rspec-support (~> 3.9.0)
28
+ rspec-support (3.9.3)
29
29
 
30
30
  PLATFORMS
31
31
  ruby
32
32
 
33
33
  DEPENDENCIES
34
- bundler (~> 2.0)
34
+ bundler (~> 2.1)
35
35
  portrayal!
36
- pry (~> 0.12)
37
- rake (~> 10.0)
38
- rspec (~> 3.0)
36
+ pry (~> 0.13)
37
+ rake (~> 13.0)
38
+ rspec (~> 3.9)
39
39
 
40
40
  BUNDLED WITH
41
- 2.0.1
41
+ 2.1.4
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ ![RSpec](https://github.com/scottscheapflights/portrayal/workflows/RSpec/badge.svg?branch=master)
2
+
1
3
  # Portrayal
2
4
 
3
5
  Inspired by:
@@ -6,7 +8,7 @@ Inspired by:
6
8
  - Piotr Solnica's [virtus](https://github.com/solnic/virtus)
7
9
  - Everything [Michel Martens](https://github.com/soveran)
8
10
 
9
- Portrayal is a minimalist gem (~120 loc, no dependencies) for building struct-like classes. It provides a small yet powerful step up from plain ruby with its one and only `keyword` method.
11
+ Portrayal is a minimalist gem (~115 loc, no dependencies) for building struct-like classes. It provides a small yet powerful step up from plain ruby with its one and only `keyword` method.
10
12
 
11
13
  ```ruby
12
14
  class Person < MySuperClass
@@ -30,8 +32,12 @@ end
30
32
  When you call `keyword`:
31
33
 
32
34
  * It defines an `attr_reader`
35
+ * It defines a protected `attr_writer`
33
36
  * It defines `initialize`
34
37
  * It defines `==` and `eql?`
38
+ * It defines `#hash` for hash equality
39
+ * It defines `#dup` and `#clone` that propagate to all keyword values
40
+ * It defines `#freeze` that propagates to all keyword values
35
41
  * It creates a nested class when you supply a block
36
42
  * It inherits parent's superclass when creating a nested class
37
43
 
@@ -39,7 +45,8 @@ The code above produces almost exactly the following ruby. There's a lot of boil
39
45
 
40
46
  ```ruby
41
47
  class Person < MySuperClass
42
- attr_reader :name, :age, :favorite_fruit, :address
48
+ attr_accessor :name, :age, :favorite_fruit, :address
49
+ protected :name=, :age=, :favorite_fruit=, :address=
43
50
 
44
51
  def initialize(name:, age: nil, favorite_fruit: 'feijoa', address:)
45
52
  @name = name
@@ -48,16 +55,46 @@ class Person < MySuperClass
48
55
  @address = address
49
56
  end
50
57
 
58
+ def eql?(other)
59
+ self.class == other.class && self == other
60
+ end
61
+
51
62
  def ==(other)
52
- self.class == other.class &&
53
- { name: name, age: age, favorite_fruit: favorite_fruit, address: address } ==
63
+ { name: name, age: age, favorite_fruit: favorite_fruit, address: address } ==
54
64
  { name: other.name, age: other.age, favorite_fruit: other.favorite_fruit, address: other.address }
55
65
  end
56
66
 
57
- alias eql? ==
67
+ def hash
68
+ [ self.class, { name: name, age: age, favorite_fruit: favorite_fruit, address: address } ].hash
69
+ end
70
+
71
+ def freeze
72
+ name.freeze
73
+ age.freeze
74
+ favorite_fruit.freeze
75
+ address.freeze
76
+ super
77
+ end
78
+
79
+ def initialize_dup(source)
80
+ @name = source.name.dup
81
+ @age = source.age.dup
82
+ @favorite_fruit = source.favorite_fruit.dup
83
+ @address = source.address.dup
84
+ super
85
+ end
86
+
87
+ def initialize_clone(source)
88
+ @name = source.name.clone
89
+ @age = source.age.clone
90
+ @favorite_fruit = source.favorite_fruit.clone
91
+ @address = source.address.clone
92
+ super
93
+ end
58
94
 
59
95
  class Address < MySuperClass
60
- attr_reader :street, :city
96
+ attr_accessor :street, :city
97
+ protected :street=, :city=
61
98
 
62
99
  def initialize(street:, city:)
63
100
  @street = street
@@ -68,12 +105,35 @@ class Person < MySuperClass
68
105
  "#{street}, #{city}"
69
106
  end
70
107
 
108
+ def eql?(other)
109
+ self.class == other.class && self == other
110
+ end
111
+
71
112
  def ==(other)
72
- self.class == other.class &&
73
- { street: street, city: city } == { street: other.street, city: other.city }
113
+ { street: street, city: city } == { street: other.street, city: other.city }
74
114
  end
75
115
 
76
- alias eql? ==
116
+ def hash
117
+ [ self.class, { street: street, city: city } ].hash
118
+ end
119
+
120
+ def freeze
121
+ street.freeze
122
+ city.freeze
123
+ super
124
+ end
125
+
126
+ def initialize_dup(source)
127
+ @street = source.street.dup
128
+ @city = source.city.dup
129
+ super
130
+ end
131
+
132
+ def initialize_clone(source)
133
+ @street = source.street.clone
134
+ @city = source.city.clone
135
+ super
136
+ end
77
137
  end
78
138
  end
79
139
  ```
@@ -7,30 +7,20 @@ module Portrayal
7
7
  @equality_defined = false
8
8
  end
9
9
 
10
- def [](name)
11
- @schema[name]
12
- end
13
-
14
- def keywords
15
- @schema.keys
16
- end
10
+ def keywords; @schema.keys end
11
+ def [](name); @schema[name] end
17
12
 
18
13
  def attributes(object)
19
- Hash[
20
- object.class.portrayal.keywords.map { |key| [key, object.send(key)] }
21
- ]
14
+ Hash[object.class.portrayal.keywords.map { |k| [k, object.send(k)] }]
22
15
  end
23
16
 
24
17
  def add_keyword(name, optional, default)
25
18
  optional, default =
26
- if optional == NULL && default == NULL
27
- [false, nil]
28
- elsif optional != NULL && default == NULL
29
- [optional, optional ? [:return, nil] : nil]
30
- elsif optional == NULL && default != NULL
31
- [true, [default_strategy(default), default]]
32
- else
33
- [optional, optional ? [default_strategy(default), default] : nil]
19
+ case [optional == NULL, default == NULL]
20
+ when [true, true]; [false, nil]
21
+ when [false, true]; [optional, optional ? [:return, nil] : nil]
22
+ when [true, false]; [true, [default_strategy(default), default]]
23
+ else; [optional, optional ? [default_strategy(default), default] : nil]
34
24
  end
35
25
 
36
26
  @schema[name.to_sym] = { optional: optional, default: default }
@@ -50,44 +40,46 @@ module Portrayal
50
40
  end
51
41
 
52
42
  def definition_of_initialize
53
- init_args =
54
- @schema
55
- .map { |name, config|
56
- if config[:optional]
57
- "#{name}: self.class.portrayal.get_default(:#{name})"
58
- else
59
- "#{name}:"
60
- end
61
- }
62
- .join(',')
63
-
64
- init_assignments =
65
- @schema
66
- .keys
67
- .map { |name| "@#{name} = #{name}" }
68
- .join('; ')
69
-
70
- "def initialize(#{init_args}); #{init_assignments} end"
43
+ init_args = @schema.map { |name, config|
44
+ config[:optional] ?
45
+ "#{name}: self.class.portrayal.get_default(:#{name})" : "#{name}:"
46
+ }.join(',')
47
+
48
+ init_assigns = @schema.keys.map { |name| "@#{name} = #{name}" }.join('; ')
49
+ "def initialize(#{init_args}); #{init_assigns} end"
71
50
  end
72
51
 
73
- def definition_of_equality
52
+ def definition_of_object_enhancements
74
53
  <<-RUBY
54
+ def eql?(other); self.class == other.class && self == other end
55
+ def hash; [self.class, self.class.portrayal.attributes(self)].hash end
56
+
75
57
  def ==(other)
76
- self.class == other.class &&
77
- self.class.portrayal.attributes(self) ==
58
+ return super unless other.class.is_a?(Portrayal)
59
+
60
+ self.class.portrayal.attributes(self) ==
78
61
  self.class.portrayal.attributes(other)
79
62
  end
80
63
 
81
- alias eql? ==
82
- RUBY
83
- end
64
+ def freeze
65
+ self.class.portrayal.attributes(self).values.each(&:freeze)
66
+ super
67
+ end
84
68
 
85
- def equality_defined?
86
- @equality_defined
87
- end
69
+ def initialize_dup(source)
70
+ self.class.portrayal.attributes(source).each do |key, value|
71
+ instance_variable_set('@' + key.to_s, value.dup)
72
+ end
73
+ super
74
+ end
88
75
 
89
- def mark_equality_defined
90
- @equality_defined = true
76
+ def initialize_clone(source)
77
+ self.class.portrayal.attributes(source).each do |key, value|
78
+ instance_variable_set('@' + key.to_s, value.clone)
79
+ end
80
+ super
81
+ end
82
+ RUBY
91
83
  end
92
84
  end
93
85
  end
@@ -1,3 +1,3 @@
1
1
  module Portrayal
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/portrayal.rb CHANGED
@@ -8,18 +8,15 @@ module Portrayal
8
8
  unless respond_to?(:portrayal)
9
9
  class << self; attr_reader :portrayal end
10
10
  @portrayal = Schema.new
11
+ class_eval(portrayal.definition_of_object_enhancements)
11
12
  end
12
13
 
13
- attr_reader name
14
+ attr_accessor name
15
+ protected "#{name}="
14
16
 
15
17
  portrayal.add_keyword(name, optional, default)
16
18
  class_eval(portrayal.definition_of_initialize)
17
19
 
18
- unless portrayal.equality_defined?
19
- class_eval(portrayal.definition_of_equality)
20
- portrayal.mark_equality_defined
21
- end
22
-
23
20
  if block_given?
24
21
  keyword_class = Class.new(superclass) { extend Portrayal }
25
22
  keyword_class.class_eval(&block)
data/portrayal.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ['madfancier@gmail.com']
10
10
 
11
11
  spec.summary = 'A minimal builder for struct-like classes'
12
- spec.description = 'Inspired by dry-initializer and virtus, portrayal is a minimalist gem (~120 loc, no dependencies) that takes a somewhat different approach to building struct-like classes. It steps away from types, coersion, and writer methods in favor of encouraging well-designed constructors. Read more in the Philosophy section of the README.'
12
+ spec.description = 'Inspired by dry-initializer and virtus, portrayal is a minimalist gem that takes a somewhat different approach to building struct-like classes. It steps away from types, coersion, and writer methods in favor of encouraging well-designed constructors. Read more in the Philosophy section of the README.'
13
13
  spec.homepage = 'https://github.com/scottscheapflights/portrayal'
14
14
  spec.license = 'Apache-2.0'
15
15
 
@@ -18,8 +18,8 @@ Gem::Specification.new do |spec|
18
18
  end
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency 'bundler', '~> 2.0'
22
- spec.add_development_dependency 'rake', '~> 10.0'
23
- spec.add_development_dependency 'rspec', '~> 3.0'
24
- spec.add_development_dependency 'pry', '~> 0.12'
21
+ spec.add_development_dependency 'bundler', '~> 2.1'
22
+ spec.add_development_dependency 'rake', '~> 13.0'
23
+ spec.add_development_dependency 'rspec', '~> 3.9'
24
+ spec.add_development_dependency 'pry', '~> 0.13'
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: portrayal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxim Chernyak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-03 00:00:00.000000000 Z
11
+ date: 2020-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,70 +16,69 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: '2.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.0'
47
+ version: '3.9'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '3.9'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.12'
61
+ version: '0.13'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.12'
68
+ version: '0.13'
69
69
  description: Inspired by dry-initializer and virtus, portrayal is a minimalist gem
70
- (~120 loc, no dependencies) that takes a somewhat different approach to building
71
- struct-like classes. It steps away from types, coersion, and writer methods in favor
72
- of encouraging well-designed constructors. Read more in the Philosophy section of
73
- the README.
70
+ that takes a somewhat different approach to building struct-like classes. It steps
71
+ away from types, coersion, and writer methods in favor of encouraging well-designed
72
+ constructors. Read more in the Philosophy section of the README.
74
73
  email:
75
74
  - madfancier@gmail.com
76
75
  executables: []
77
76
  extensions: []
78
77
  extra_rdoc_files: []
79
78
  files:
79
+ - ".github/workflows/rspec.yml"
80
80
  - ".gitignore"
81
81
  - ".rspec"
82
- - ".travis.yml"
83
82
  - CHANGELOG.md
84
83
  - CODE_OF_CONDUCT.md
85
84
  - Gemfile
@@ -112,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
111
  - !ruby/object:Gem::Version
113
112
  version: '0'
114
113
  requirements: []
115
- rubygems_version: 3.0.3
114
+ rubygems_version: 3.1.2
116
115
  signing_key:
117
116
  specification_version: 4
118
117
  summary: A minimal builder for struct-like classes
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.3
7
- - 2.4
8
- - 2.5
9
- - 2.6
10
- before_install: gem install bundler -v 2.0.1