portrayal 0.7.0 → 0.8.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: fbd0b561e866c45f6e850b592620df78d4573635165807cd2284ab45baed9e0c
4
- data.tar.gz: 699be912aa836a55faa10886a3a1c1bb7b17c006f1db445694660d2fbe0ec0f4
3
+ metadata.gz: 6e6b15fe5bee4f60e8369a839ecad908c35bdbba34559e324f71c3a8404586ad
4
+ data.tar.gz: 279dc9030eea091d806fa9e02178783d02063c6efc731bc601a48a68e50f8281
5
5
  SHA512:
6
- metadata.gz: 58fc168ad299aee9555ec7e1a1355f533c65af5ff1620095a7e49829252b39e92f45714083cc03fd1cde2ccc027acabd98b3526618caae07fb226be7e294694b
7
- data.tar.gz: 8d59938b7bdcc5b9a32683695b6146186cb12bf6132326ecfff5b01685b7740dbf78ef513a43fbf5ff58716c38848881229600e4eb2f059dc13efc530120d68d
6
+ metadata.gz: a3c414e415b48127c4f86ee41b7b5d0eed7730ea7316c356afa533f539acd42bdf70c08e1c64f78ddd7ba444da47f4069dbdf8716d42592a8d1b15ec38ca7ff4
7
+ data.tar.gz: 2fdab00d88f76ae116af03e14d883346797cf60c21ab0569823f6dd869f3efe368db1b9b2d1e41548619e1666de8acf38d555647a2e29270f0c35e6e512d7aa8
@@ -1,24 +1,18 @@
1
1
  name: RSpec
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
- pull_request:
7
- branches: [ main ]
8
-
2
+ on: [push, pull_request]
9
3
  jobs:
10
4
  test:
11
5
  runs-on: ubuntu-latest
12
6
  strategy:
7
+ fail-fast: false
13
8
  matrix:
14
- ruby: [ '2.4', '2.5', '2.6', '2.7' ]
9
+ ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0', '3.2' ]
15
10
 
16
11
  name: Ruby ${{ matrix.ruby }}
17
12
  steps:
18
- - uses: actions/checkout@v2
19
- - uses: actions/setup-ruby@v1
13
+ - uses: actions/checkout@v3
14
+ - uses: ruby/setup-ruby@v1
20
15
  with:
21
16
  ruby-version: ${{ matrix.ruby }}
22
- - run: gem install bundler
23
- - run: bundle install
17
+ bundler-cache: true
24
18
  - run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.8.0 - 2023-01-27
6
+
7
+ * Add pattern matching support (`#deconstruct` and `#deconstruct_keys`).
8
+
9
+ ## 0.7.1 - 2021-03-22
10
+
11
+ * Fix default procs' behavior when overriding keywords in subclasses. Portrayal relies on an ordered ruby hash to initialize keywords in the correct order. However, if overriding the same keyword in a subclass (by declaring it again), it didn't move keyword to the bottom of the hash, so this would happen:
12
+
13
+ ```ruby
14
+ class Person
15
+ extend Portrayal
16
+ keyword :email, default: nil
17
+ end
18
+
19
+ class Employee < Person
20
+ keyword :employee_id
21
+ keyword :email, default: proc { "#{employee_id}@example.com" }
22
+ end
23
+
24
+ employee = Employee.new(employee_id: '1234')
25
+ employee.email # => "@example.com"
26
+ ```
27
+
28
+ The email is broken because it relies on having employee_id declared before email, but email was already declared first in the superclass. This change fixes situations like this by re-adding the keyword to the bottom of the hash on every re-declaration.
29
+
5
30
  ## 0.7.0 - 2020-12-13
6
31
 
7
32
  * **Breaking change:** Remove `optional` setting. To update find all `optional: true` and change to `default: nil` instead.
@@ -10,31 +35,31 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
10
35
 
11
36
  ## 0.6.0 - 2020-08-10
12
37
 
13
- * Return keyword name from `keyword`, allowing usage such as `private keyword :foo`. [[commit]](https://github.com/scottscheapflights/portrayal/commit/9e9db2cafc7eae14789c5b84f70efd18898ace76)
38
+ * Return keyword name from `keyword`, allowing usage such as `private keyword :foo`. [[commit]](https://github.com/maxim/portrayal/commit/9e9db2cafc7eae14789c5b84f70efd18898ace76)
14
39
 
15
40
  ## 0.5.0 - 2020-05-28
16
41
 
17
- * Add option `define` for overriding nested class name. [[commit]](https://github.com/scottscheapflights/portrayal/commit/665ad297fb71fcdf5f641c672a457ccbe29e4a49)
42
+ * Add option `define` for overriding nested class name. [[commit]](https://github.com/maxim/portrayal/commit/665ad297fb71fcdf5f641c672a457ccbe29e4a49)
18
43
 
19
44
  ## 0.4.0 - 2020-05-16
20
45
 
21
- * Portrayal schema is deep-duped to subclasses. [[commit]](https://github.com/scottscheapflights/portrayal/commit/f346483a379ce9fbdece72cde8b0844f2d22b1cd)
46
+ * Portrayal schema is deep-duped to subclasses. [[commit]](https://github.com/maxim/portrayal/commit/f346483a379ce9fbdece72cde8b0844f2d22b1cd)
22
47
 
23
48
  ## 0.3.1 - 2020-05-11
24
49
 
25
- * Fix the issue introduced in 0.3.0 where `==` and `eql?` were always treating rhs as another portrayal class. [[commit]](https://github.com/scottscheapflights/portrayal/commit/f6ec8f373c6582f7e8d8f872d289222e4a58f8f6)
50
+ * Fix the issue introduced in 0.3.0 where `==` and `eql?` were always treating rhs as another portrayal class. [[commit]](https://github.com/maxim/portrayal/commit/f6ec8f373c6582f7e8d8f872d289222e4a58f8f6)
26
51
 
27
52
  ## 0.3.0 - 2020-05-09 (yanked)
28
53
 
29
- * No longer compare classes in `==`, use `eql?` for that. [[commit]](https://github.com/scottscheapflights/portrayal/commit/9c5a37e4fb91e35d23b22e208344452930452af7)
30
- * Define a protected writer for every keyword - useful when applying changes after `dup`/`clone`. [[commit]](https://github.com/scottscheapflights/portrayal/commit/1c0fa6c6357a09760dae39165e864238d231a08e)
31
- * 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)
32
- * Make `#freeze` propagate to all keyword values. [[commit]](https://github.com/scottscheapflights/portrayal/commit/0a734411a6eac08e2355c4277e09a2a70800d032)
33
- * Make `#dup` and `#clone` propagate to all keyword values. [[commit]](https://github.com/scottscheapflights/portrayal/commit/010632d87d81a8d5b5ea5ff27d3d209cc667b0a5)
54
+ * No longer compare classes in `==`, use `eql?` for that. [[commit]](https://github.com/maxim/portrayal/commit/9c5a37e4fb91e35d23b22e208344452930452af7)
55
+ * Define a protected writer for every keyword - useful when applying changes after `dup`/`clone`. [[commit]](https://github.com/maxim/portrayal/commit/1c0fa6c6357a09760dae39165e864238d231a08e)
56
+ * 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/maxim/portrayal/commit/ba9e390ab4aea4733ba084ac273da448e313ea53)
57
+ * Make `#freeze` propagate to all keyword values. [[commit]](https://github.com/maxim/portrayal/commit/0a734411a6eac08e2355c4277e09a2a70800d032)
58
+ * Make `#dup` and `#clone` propagate to all keyword values. [[commit]](https://github.com/maxim/portrayal/commit/010632d87d81a8d5b5ea5ff27d3d209cc667b0a5)
34
59
 
35
60
  ## 0.2.0 - 2019-07-03
36
61
 
37
- * 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)
62
+ * 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/maxim/portrayal/commit/a1cc9d0fd40e413210f61b945d37b81c87280fee)
38
63
 
39
64
  ## 0.1.0
40
65
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![RSpec](https://github.com/scottscheapflights/portrayal/workflows/RSpec/badge.svg)
1
+ ![RSpec](https://github.com/maxim/portrayal/workflows/RSpec/badge.svg)
2
2
 
3
3
  # Portrayal
4
4
 
@@ -8,7 +8,7 @@ Inspired by:
8
8
  - Piotr Solnica's [virtus](https://github.com/solnic/virtus)
9
9
  - Everything [Michel Martens](https://github.com/soveran)
10
10
 
11
- 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 (~130 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.
12
12
 
13
13
  ```ruby
14
14
  class Person < MySuperClass
@@ -263,6 +263,79 @@ end
263
263
 
264
264
  This defines `Person::Country`, while the accessor remains `visited_countries`.
265
265
 
266
+ ### Subclassing
267
+
268
+ Portrayal supports subclassing.
269
+
270
+ ```ruby
271
+ class Person
272
+ extend Portrayal
273
+
274
+ class << self
275
+ def from_contact(contact)
276
+ new name: contact.full_name,
277
+ address: contact.address.to_s,
278
+ email: contact.email
279
+ end
280
+ end
281
+
282
+ keyword :name
283
+ keyword :address
284
+ keyword :email, default: nil
285
+ end
286
+ ```
287
+
288
+ ```ruby
289
+ class Employee < Person
290
+ keyword :employee_id
291
+ keyword :email, default: proc { "#{employee_id}@example.com" }
292
+ end
293
+ ```
294
+
295
+ Now when you call `Employee.new` it will accept keywords of both superclass and subclass. You can also see how `email`'s default is overridden in the subclass.
296
+
297
+ However, if you try calling `Employee.from_contact(contact)` it will error out, because that constructor doesn't set an `employee_id` required in the subclass. You can remedy that with a small change.
298
+
299
+ ```ruby
300
+ def from_contact(contact, **kwargs)
301
+ new name: contact.full_name,
302
+ address: contact.address.to_s,
303
+ email: contact.email,
304
+ **kwargs
305
+ end
306
+ ```
307
+
308
+ If you add `**kwargs` to `Person.from_contact` and pass them through to new, then you are now able to call `Employee.from_contact(contact, employee_id: 'some_id')`
309
+
310
+ ### Pattern Matching
311
+
312
+ If your Ruby has pattern matching, you can pattern match portrayal objects. Both array- and hash-style matching are supported.
313
+
314
+ ```ruby
315
+ class Point
316
+ extend Portrayal
317
+
318
+ keyword :x
319
+ keyword :y
320
+ end
321
+
322
+ point = Point.new(x: 5, y: 10)
323
+
324
+ case point
325
+ in 5, 10
326
+ 'matched'
327
+ else
328
+ 'did not match'
329
+ end # => "matched"
330
+
331
+ case point
332
+ in x:, y: 10
333
+ 'matched'
334
+ else
335
+ 'did not match'
336
+ end # => "matched"
337
+ ```
338
+
266
339
  ### Schema
267
340
 
268
341
  Every class that has at least one keyword defined in it automatically receives a class method called `portrayal`. This method is a schema of your object with some additional helpers.
@@ -387,7 +460,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
387
460
 
388
461
  ## Contributing
389
462
 
390
- Bug reports and pull requests are welcome on GitHub at https://github.com/scottscheapflights/portrayal. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
463
+ Bug reports and pull requests are welcome on GitHub at https://github.com/maxim/portrayal. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
391
464
 
392
465
  ## License
393
466
 
@@ -395,4 +468,4 @@ The gem is available as open source under the terms of the [Apache License Versi
395
468
 
396
469
  ## Code of Conduct
397
470
 
398
- Everyone interacting in the Portrayal project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/scottscheapflights/portrayal/blob/main/CODE_OF_CONDUCT.md).
471
+ Everyone interacting in the Portrayal project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/maxim/portrayal/blob/main/CODE_OF_CONDUCT.md).
data/bin/loc ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bash
2
+ find lib -name '*.rb' | xargs wc -l
@@ -7,6 +7,13 @@ module Portrayal
7
7
  DEFINITION_OF_OBJECT_ENHANCEMENTS = <<~RUBY.freeze
8
8
  def eql?(other); self.class == other.class && self == other end
9
9
  def hash; [self.class, self.class.portrayal.attributes(self)].hash end
10
+ def deconstruct; self.class.portrayal.attributes(self).values end
11
+
12
+ def deconstruct_keys(keys)
13
+ keys ||= self.class.portrayal.keywords
14
+ keys &= self.class.portrayal.keywords
15
+ Hash[keys.map { |k| [k, send(k)] }]
16
+ end
10
17
 
11
18
  def ==(other)
12
19
  return super unless other.class.is_a?(Portrayal)
@@ -46,7 +53,9 @@ module Portrayal
46
53
  def camelize(string); string.to_s.gsub(/(?:^|_+)([^_])/) { $1.upcase } end
47
54
 
48
55
  def add_keyword(name, default)
49
- @schema[name.to_sym] = default.equal?(NULL) ? nil : Default.new(default)
56
+ name = name.to_sym
57
+ @schema.delete(name) # Forcing keyword to be added at the end of the hash.
58
+ @schema[name] = default.equal?(NULL) ? nil : Default.new(default)
50
59
  end
51
60
 
52
61
  def initialize_dup(other)
@@ -1,3 +1,3 @@
1
1
  module Portrayal
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
data/portrayal.gemspec CHANGED
@@ -3,17 +3,17 @@ require_relative 'lib/portrayal/version'
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'portrayal'
5
5
  spec.version = Portrayal::VERSION
6
- spec.authors = ['Maxim Chernyak']
7
- spec.email = ['madfancier@gmail.com']
6
+ spec.authors = ['Max Chernyak']
7
+ spec.email = ['hello@max.engineer']
8
8
 
9
9
  spec.summary = 'A minimal builder for struct-like classes'
10
10
  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.'
11
- spec.homepage = 'https://github.com/scottscheapflights/portrayal'
11
+ spec.homepage = 'https://github.com/maxim/portrayal'
12
12
  spec.license = 'Apache-2.0'
13
13
 
14
14
  spec.metadata['homepage_uri'] = spec.homepage
15
15
  spec.metadata['source_code_uri'] = spec.homepage
16
- spec.metadata['changelog_uri'] = 'https://github.com/scottscheapflights/portrayal/blob/main/CHANGELOG.md'
16
+ spec.metadata['changelog_uri'] = 'https://github.com/maxim/portrayal/blob/main/CHANGELOG.md'
17
17
 
18
18
  spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
19
19
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
@@ -21,8 +21,7 @@ Gem::Specification.new do |spec|
21
21
  end
22
22
  spec.require_paths = ['lib']
23
23
 
24
- spec.add_development_dependency 'bundler', '~> 2.1'
25
24
  spec.add_development_dependency 'rake', '~> 13.0'
26
- spec.add_development_dependency 'rspec', '~> 3.9'
27
- spec.add_development_dependency 'pry', '~> 0.13'
25
+ spec.add_development_dependency 'rspec', '~> 3.12'
26
+ spec.add_development_dependency 'pry', '~> 0.14'
28
27
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: portrayal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
- - Maxim Chernyak
7
+ - Max Chernyak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-13 00:00:00.000000000 Z
11
+ date: 2023-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.1'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.1'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rake
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -44,34 +30,34 @@ dependencies:
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: '3.9'
33
+ version: '3.12'
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: '3.9'
40
+ version: '3.12'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: pry
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '0.13'
47
+ version: '0.14'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '0.13'
54
+ version: '0.14'
69
55
  description: Inspired by dry-initializer and virtus, portrayal is a minimalist gem
70
56
  that takes a somewhat different approach to building struct-like classes. It steps
71
57
  away from types, coersion, and writer methods in favor of encouraging well-designed
72
58
  constructors. Read more in the Philosophy section of the README.
73
59
  email:
74
- - madfancier@gmail.com
60
+ - hello@max.engineer
75
61
  executables: []
76
62
  extensions: []
77
63
  extra_rdoc_files: []
@@ -86,19 +72,20 @@ files:
86
72
  - README.md
87
73
  - Rakefile
88
74
  - bin/console
75
+ - bin/loc
89
76
  - bin/setup
90
77
  - lib/portrayal.rb
91
78
  - lib/portrayal/default.rb
92
79
  - lib/portrayal/schema.rb
93
80
  - lib/portrayal/version.rb
94
81
  - portrayal.gemspec
95
- homepage: https://github.com/scottscheapflights/portrayal
82
+ homepage: https://github.com/maxim/portrayal
96
83
  licenses:
97
84
  - Apache-2.0
98
85
  metadata:
99
- homepage_uri: https://github.com/scottscheapflights/portrayal
100
- source_code_uri: https://github.com/scottscheapflights/portrayal
101
- changelog_uri: https://github.com/scottscheapflights/portrayal/blob/main/CHANGELOG.md
86
+ homepage_uri: https://github.com/maxim/portrayal
87
+ source_code_uri: https://github.com/maxim/portrayal
88
+ changelog_uri: https://github.com/maxim/portrayal/blob/main/CHANGELOG.md
102
89
  post_install_message:
103
90
  rdoc_options: []
104
91
  require_paths:
@@ -114,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
101
  - !ruby/object:Gem::Version
115
102
  version: '0'
116
103
  requirements: []
117
- rubygems_version: 3.1.2
104
+ rubygems_version: 3.4.2
118
105
  signing_key:
119
106
  specification_version: 4
120
107
  summary: A minimal builder for struct-like classes