attr_extras 4.4.0 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/README.md +62 -8
- data/attr_extras.gemspec +1 -0
- data/lib/attr_extras/attr_implement.rb +32 -0
- data/lib/attr_extras/explicit.rb +12 -23
- data/lib/attr_extras/version.rb +1 -1
- data/script/test +2 -5
- data/spec/attr_extras/aattr_initialize_spec.rb +58 -0
- data/spec/attr_extras/pattr_initialize_spec.rb +1 -1
- data/spec/attr_extras/rattr_initialize_spec.rb +1 -1
- data/spec/attr_extras/vattr_initialize_spec.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a8bcd34f935912a3cf97f5a31b39330e357aa61
|
4
|
+
data.tar.gz: f99cb0a632963344367f906285cc572b913932a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 796bdd29576ca722747c2b2508571f6ab60197741e1dbf91532f4f6cdcbcfcc478e81d3ffb41e72345a22d5319eb9e066879144b6eaf7624bd0dd6765223d5aa
|
7
|
+
data.tar.gz: 5b0a456b2657f7a33823b98b864821ab8845296e63d459d661cce67d7d2b2a296208cb7097e34209bd4063510c79dc9f3906fbe8cd7ad7bce6265e1de7faca11
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -42,6 +42,7 @@ Also provides conveniences for creating value objects, method objects, query met
|
|
42
42
|
* [`pattr_initialize`](#pattr_initialize) / [`attr_private_initialize`](#attr_private_initialize)
|
43
43
|
* [`vattr_initialize`](#vattr_initialize) / [`attr_value_initialize`](#attr_value_initialize)
|
44
44
|
* [`rattr_initialize`](#rattr_initialize) / [`attr_reader_initialize`](#attr_reader_initialize)
|
45
|
+
* [`aattr_initialize`](#aattr_initialize) / [`attr_accessor_initialize`](#attr_accessor_initialize)
|
45
46
|
* [`static_facade`](#static_facade)
|
46
47
|
* [`method_object`](#method_object)
|
47
48
|
* [`attr_implement`](#attr_implement)
|
@@ -57,7 +58,7 @@ Also provides conveniences for creating value objects, method objects, query met
|
|
57
58
|
|
58
59
|
`attr_initialize [:bar, :baz!]` defines an initializer that takes one hash argument, assigning `@bar` (optional) and `@baz` (required).
|
59
60
|
|
60
|
-
`attr_initialize` can also accept a block which will be invoked after initialization. This is useful for
|
61
|
+
`attr_initialize` can also accept a block which will be invoked after initialization. This is useful for e.g. initializing private data as necessary.
|
61
62
|
|
62
63
|
|
63
64
|
### `attr_private`
|
@@ -88,7 +89,7 @@ Example:
|
|
88
89
|
|
89
90
|
``` ruby
|
90
91
|
class Item
|
91
|
-
|
92
|
+
pattr_initialize :name, :price
|
92
93
|
|
93
94
|
def price_with_vat
|
94
95
|
price * 1.25
|
@@ -142,19 +143,47 @@ Example:
|
|
142
143
|
|
143
144
|
``` ruby
|
144
145
|
class PublishBook
|
145
|
-
|
146
|
+
rattr_initialize :book_name, :publisher_backend
|
146
147
|
|
147
148
|
def call
|
148
149
|
publisher_backend.publish book_name
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
152
|
-
service = PublishBook.new("A Novel")
|
153
|
+
service = PublishBook.new("A Novel", publisher)
|
153
154
|
service.book_name # => "A Novel"
|
154
155
|
```
|
155
156
|
|
156
157
|
[The `attr_initialize` notation](#attr_initialize) for hash arguments is also supported: `rattr_initialize :foo, [:bar, :baz!]`
|
157
158
|
|
159
|
+
### `aattr_initialize`
|
160
|
+
### `attr_accessor_initialize`
|
161
|
+
|
162
|
+
`aattr_initialize :foo, :bar` defines an initializer, public readers, and public writers. It's a shortcut for:
|
163
|
+
|
164
|
+
``` ruby
|
165
|
+
attr_initialize :foo, :bar
|
166
|
+
attr_accessor :foo, :bar
|
167
|
+
```
|
168
|
+
|
169
|
+
`aattr_initialize` is aliased as `attr_accessor_initialize`, if you prefer a longer but clearer name.
|
170
|
+
|
171
|
+
Example:
|
172
|
+
|
173
|
+
``` ruby
|
174
|
+
class Client
|
175
|
+
aattr_initialize :username, :access_token
|
176
|
+
end
|
177
|
+
|
178
|
+
client = Client.new("barsoom", "SECRET")
|
179
|
+
client.username # => "barsoom"
|
180
|
+
|
181
|
+
client.access_token = "NEW_SECRET"
|
182
|
+
client.access_token # => "NEW_SECRET"
|
183
|
+
```
|
184
|
+
|
185
|
+
[The `attr_initialize` notation](#attr_initialize) for hash arguments and blocks is also supported.
|
186
|
+
|
158
187
|
### `static_facade`
|
159
188
|
|
160
189
|
`static_facade :allow?, :user` defines an `.allow?` class method that delegates to an instance method by the same name, having first provided `user` as a private reader.
|
@@ -275,6 +304,23 @@ end
|
|
275
304
|
|
276
305
|
though it is shorter, more declarative, gives you a clear message and handles edge cases you might not have thought about (see tests).
|
277
306
|
|
307
|
+
Note that you can also use this with modules, to effectively mix in interfaces:
|
308
|
+
|
309
|
+
``` ruby
|
310
|
+
module Bookable
|
311
|
+
attr_implement :book, [:bookable]
|
312
|
+
attr_implement :booked?
|
313
|
+
end
|
314
|
+
|
315
|
+
class Invoice
|
316
|
+
include Bookable
|
317
|
+
end
|
318
|
+
|
319
|
+
class Payment
|
320
|
+
include Bookable
|
321
|
+
end
|
322
|
+
```
|
323
|
+
|
278
324
|
|
279
325
|
### `attr_query`
|
280
326
|
|
@@ -294,7 +340,7 @@ This is not ideal if you're using attr\_extras in a library: those who depend on
|
|
294
340
|
|
295
341
|
It's also not obvious where the methods come from. You can be more explicit about it, and restrict where the methods are added, like this:
|
296
342
|
|
297
|
-
```
|
343
|
+
``` ruby
|
298
344
|
require "attr_extras/explicit"
|
299
345
|
|
300
346
|
class MyLib
|
@@ -306,7 +352,7 @@ end
|
|
306
352
|
|
307
353
|
Crucially, you need to `require "attr_extras/explicit"` *instead of* `require "attr_extras"`. Some frameworks, like Ruby on Rails, may automatically require everything in your `Gemfile`. You can avoid that with `gem "attr_extras", require: "attr_extras/explicit"`.
|
308
354
|
|
309
|
-
In explicit mode, you need to call `extend AttrExtras.mixin` *in every class* that wants the attr\_extras methods.
|
355
|
+
In explicit mode, you need to call `extend AttrExtras.mixin` *in every class or module* that wants the attr\_extras methods.
|
310
356
|
|
311
357
|
|
312
358
|
## Philosophy
|
@@ -330,6 +376,10 @@ Other than being more to type, declaring `attr_reader` after `private` will actu
|
|
330
376
|
|
331
377
|
If you don't want the dependency on `attr_extras`, you can get rid of the warnings with `attr_reader :foo; private :foo`. Or just define a regular private method.
|
332
378
|
|
379
|
+
### Can I use attr\_extras in `BasicObject`s?
|
380
|
+
|
381
|
+
No, sorry. It depends on various methods that `BasicObject`s don't have. Use a regular `Object` or make do without attr\_extras.
|
382
|
+
|
333
383
|
|
334
384
|
## Installation
|
335
385
|
|
@@ -350,11 +400,15 @@ Or install it yourself as:
|
|
350
400
|
|
351
401
|
Run them with:
|
352
402
|
|
353
|
-
|
403
|
+
rake
|
354
404
|
|
355
405
|
Or to see warnings (try not to have any):
|
356
406
|
|
357
|
-
|
407
|
+
RUBYOPT=-w rake
|
408
|
+
|
409
|
+
You can run an individual test using the [m](https://github.com/qrush/m) gem:
|
410
|
+
|
411
|
+
m spec/attr_extras/attr_initialize_spec.rb:48
|
358
412
|
|
359
413
|
The tests are intentionally split into two test suites for reasons described in `Rakefile`.
|
360
414
|
|
data/attr_extras.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = AttrExtras::VERSION
|
17
17
|
|
18
18
|
gem.add_development_dependency "minitest", ">= 5"
|
19
|
+
gem.add_development_dependency "m", "~> 1.3.1" # Running individual tests.
|
19
20
|
|
20
21
|
# For Travis CI.
|
21
22
|
gem.add_development_dependency "rake"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class AttrExtras::AttrImplement
|
2
|
+
def initialize(klass, names)
|
3
|
+
@klass, @names = klass, names.dup
|
4
|
+
end
|
5
|
+
|
6
|
+
def apply
|
7
|
+
arg_names = @names.last.is_a?(Array) ? @names.pop : []
|
8
|
+
expected_arity = arg_names.length
|
9
|
+
|
10
|
+
# Make available within the block.
|
11
|
+
names = @names
|
12
|
+
|
13
|
+
mod = Module.new do
|
14
|
+
define_method :method_missing do |name, *args|
|
15
|
+
if names.include?(name)
|
16
|
+
provided_arity = args.length
|
17
|
+
|
18
|
+
if provided_arity != expected_arity
|
19
|
+
raise ArgumentError, "wrong number of arguments (#{provided_arity} for #{expected_arity})"
|
20
|
+
end
|
21
|
+
|
22
|
+
raise AttrExtras::MethodNotImplementedError, "Implement a '#{name}(#{arg_names.join(", ")})' method"
|
23
|
+
else
|
24
|
+
super(name, *args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# include is private in Ruby 2.0 and earlier.
|
30
|
+
@klass.send(:include, mod)
|
31
|
+
end
|
32
|
+
end
|
data/lib/attr_extras/explicit.rb
CHANGED
@@ -2,6 +2,7 @@ require "attr_extras/version"
|
|
2
2
|
require "attr_extras/attr_initialize"
|
3
3
|
require "attr_extras/attr_value"
|
4
4
|
require "attr_extras/attr_query"
|
5
|
+
require "attr_extras/attr_implement"
|
5
6
|
require "attr_extras/utils"
|
6
7
|
|
7
8
|
module AttrExtras
|
@@ -9,12 +10,12 @@ module AttrExtras
|
|
9
10
|
class MethodNotImplementedError < Exception; end
|
10
11
|
|
11
12
|
def self.mixin
|
12
|
-
self::
|
13
|
+
self::Mixin
|
13
14
|
end
|
14
15
|
|
15
|
-
# Separate module
|
16
|
+
# Separate module so that mixing in the methods doesn't also mix in constants:
|
16
17
|
# http://thepugautomatic.com/2014/02/private-api/
|
17
|
-
module
|
18
|
+
module Mixin
|
18
19
|
def attr_initialize(*names, &block)
|
19
20
|
AttrInitialize.new(self, names, block).apply
|
20
21
|
end
|
@@ -53,6 +54,13 @@ module AttrExtras
|
|
53
54
|
|
54
55
|
alias_method :attr_reader_initialize, :rattr_initialize
|
55
56
|
|
57
|
+
def aattr_initialize(*names, &block)
|
58
|
+
attr_initialize(*names, &block)
|
59
|
+
attr_accessor(*Utils.flat_names(names))
|
60
|
+
end
|
61
|
+
|
62
|
+
alias_method :attr_accessor_initialize, :aattr_initialize
|
63
|
+
|
56
64
|
def static_facade(method_name, *names)
|
57
65
|
define_singleton_method(method_name) do |*values|
|
58
66
|
new(*values).public_send(method_name)
|
@@ -74,26 +82,7 @@ module AttrExtras
|
|
74
82
|
end
|
75
83
|
|
76
84
|
def attr_implement(*names)
|
77
|
-
|
78
|
-
arity = arg_names.length
|
79
|
-
|
80
|
-
mod = Module.new do
|
81
|
-
define_method :method_missing do |name, *args|
|
82
|
-
if names.include?(name)
|
83
|
-
provided_arity = args.length
|
84
|
-
|
85
|
-
if provided_arity != arity
|
86
|
-
raise ArgumentError, "wrong number of arguments (#{provided_arity} for #{arity})"
|
87
|
-
end
|
88
|
-
|
89
|
-
raise MethodNotImplementedError, "Implement a '#{name}(#{arg_names.join(", ")})' method"
|
90
|
-
else
|
91
|
-
super(name, *args)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
include mod
|
85
|
+
AttrImplement.new(self, names).apply
|
97
86
|
end
|
98
87
|
end
|
99
88
|
end
|
data/lib/attr_extras/version.rb
CHANGED
data/script/test
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
#
|
4
|
-
# in this case we need to work around test unit a bit.
|
3
|
+
# This script is per the Auctionet.com developer conventions for running tests in the same way in any project.
|
5
4
|
|
6
|
-
|
7
|
-
file = ARGV.first.split(":").first
|
8
|
-
system("bundle exec ruby #{file}") || exit(1)
|
5
|
+
system("bundle exec m #{ARGV.first}") || exit(1)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Object, ".aattr_initialize" do
|
4
|
+
it "creates an initializer and public readers" do
|
5
|
+
klass = Class.new do
|
6
|
+
aattr_initialize :foo, :bar
|
7
|
+
end
|
8
|
+
|
9
|
+
example = klass.new("Foo", "Bar")
|
10
|
+
|
11
|
+
example.foo.must_equal "Foo"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "creates public writers" do
|
15
|
+
klass = Class.new do
|
16
|
+
aattr_initialize :foo, :bar
|
17
|
+
end
|
18
|
+
|
19
|
+
example = klass.new("Foo", "Bar")
|
20
|
+
example.foo = "Baz"
|
21
|
+
|
22
|
+
example.foo.must_equal "Baz"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "works with hash ivars" do
|
26
|
+
klass = Class.new do
|
27
|
+
aattr_initialize :foo, [:bar, :baz!]
|
28
|
+
end
|
29
|
+
|
30
|
+
example = klass.new("Foo", :bar => "Bar", :baz => "Baz")
|
31
|
+
|
32
|
+
example.baz.must_equal "Baz"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "accepts a block for initialization" do
|
36
|
+
klass = Class.new do
|
37
|
+
aattr_initialize :value do
|
38
|
+
@copy = @value
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :copy
|
42
|
+
end
|
43
|
+
|
44
|
+
example = klass.new("expected")
|
45
|
+
|
46
|
+
example.copy.must_equal "expected"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "accepts the alias attr_accessor_initialize" do
|
50
|
+
klass = Class.new do
|
51
|
+
attr_accessor_initialize :foo, :bar
|
52
|
+
end
|
53
|
+
|
54
|
+
example = klass.new("Foo", "Bar")
|
55
|
+
|
56
|
+
example.foo.must_equal "Foo"
|
57
|
+
end
|
58
|
+
end
|
@@ -33,7 +33,7 @@ describe Object, ".pattr_initialize" do
|
|
33
33
|
example.copy.must_equal "expected"
|
34
34
|
end
|
35
35
|
|
36
|
-
it "accepts the alias
|
36
|
+
it "accepts the alias attr_private_initialize" do
|
37
37
|
klass = Class.new do
|
38
38
|
attr_private_initialize :foo, :bar
|
39
39
|
end
|
@@ -19,7 +19,7 @@ describe Object, ".rattr_initialize" do
|
|
19
19
|
example.public_send(:baz).must_equal "Baz"
|
20
20
|
end
|
21
21
|
|
22
|
-
it "accepts the alias
|
22
|
+
it "accepts the alias attr_reader_initialize" do
|
23
23
|
klass = Class.new do
|
24
24
|
attr_reader_initialize :foo, :bar
|
25
25
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attr_extras
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrik Nyh
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2016-03-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: minitest
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '5'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: m
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.3.1
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.3.1
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: rake
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -55,6 +69,7 @@ files:
|
|
55
69
|
- Rakefile
|
56
70
|
- attr_extras.gemspec
|
57
71
|
- lib/attr_extras.rb
|
72
|
+
- lib/attr_extras/attr_implement.rb
|
58
73
|
- lib/attr_extras/attr_initialize.rb
|
59
74
|
- lib/attr_extras/attr_query.rb
|
60
75
|
- lib/attr_extras/attr_value.rb
|
@@ -62,6 +77,7 @@ files:
|
|
62
77
|
- lib/attr_extras/utils.rb
|
63
78
|
- lib/attr_extras/version.rb
|
64
79
|
- script/test
|
80
|
+
- spec/attr_extras/aattr_initialize_spec.rb
|
65
81
|
- spec/attr_extras/attr_id_query_spec.rb
|
66
82
|
- spec/attr_extras/attr_implement_spec.rb
|
67
83
|
- spec/attr_extras/attr_initialize_spec.rb
|
@@ -102,6 +118,7 @@ signing_key:
|
|
102
118
|
specification_version: 4
|
103
119
|
summary: Takes some boilerplate out of Ruby with methods like attr_initialize.
|
104
120
|
test_files:
|
121
|
+
- spec/attr_extras/aattr_initialize_spec.rb
|
105
122
|
- spec/attr_extras/attr_id_query_spec.rb
|
106
123
|
- spec/attr_extras/attr_implement_spec.rb
|
107
124
|
- spec/attr_extras/attr_initialize_spec.rb
|