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 +4 -4
- data/.github/workflows/rspec.yml +6 -12
- data/CHANGELOG.md +35 -10
- data/README.md +77 -4
- data/bin/loc +2 -0
- data/lib/portrayal/schema.rb +10 -1
- data/lib/portrayal/version.rb +1 -1
- data/portrayal.gemspec +6 -7
- metadata +14 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e6b15fe5bee4f60e8369a839ecad908c35bdbba34559e324f71c3a8404586ad
|
4
|
+
data.tar.gz: 279dc9030eea091d806fa9e02178783d02063c6efc731bc601a48a68e50f8281
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3c414e415b48127c4f86ee41b7b5d0eed7730ea7316c356afa533f539acd42bdf70c08e1c64f78ddd7ba444da47f4069dbdf8716d42592a8d1b15ec38ca7ff4
|
7
|
+
data.tar.gz: 2fdab00d88f76ae116af03e14d883346797cf60c21ab0569823f6dd869f3efe368db1b9b2d1e41548619e1666de8acf38d555647a2e29270f0c35e6e512d7aa8
|
data/.github/workflows/rspec.yml
CHANGED
@@ -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@
|
19
|
-
- uses:
|
13
|
+
- uses: actions/checkout@v3
|
14
|
+
- uses: ruby/setup-ruby@v1
|
20
15
|
with:
|
21
16
|
ruby-version: ${{ matrix.ruby }}
|
22
|
-
|
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/
|
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/
|
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/
|
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/
|
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/
|
30
|
-
* Define a protected writer for every keyword - useful when applying changes after `dup`/`clone`. [[commit]](https://github.com/
|
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/
|
32
|
-
* Make `#freeze` propagate to all keyword values. [[commit]](https://github.com/
|
33
|
-
* Make `#dup` and `#clone` propagate to all keyword values. [[commit]](https://github.com/
|
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/
|
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
|
-

|
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 (~
|
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/
|
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/
|
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
data/lib/portrayal/schema.rb
CHANGED
@@ -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
|
-
|
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)
|
data/lib/portrayal/version.rb
CHANGED
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 = ['
|
7
|
-
spec.email = ['
|
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/
|
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/
|
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.
|
27
|
-
spec.add_development_dependency 'pry', '~> 0.
|
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.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Max Chernyak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
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.
|
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.
|
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.
|
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.
|
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
|
-
-
|
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/
|
82
|
+
homepage: https://github.com/maxim/portrayal
|
96
83
|
licenses:
|
97
84
|
- Apache-2.0
|
98
85
|
metadata:
|
99
|
-
homepage_uri: https://github.com/
|
100
|
-
source_code_uri: https://github.com/
|
101
|
-
changelog_uri: https://github.com/
|
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.
|
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
|