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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a302397db869ccd71c2f96bed2c343468d4c1fb
4
- data.tar.gz: 4753ba73b9809a4f4d24943058329bb491a796ee
3
+ metadata.gz: 3a8bcd34f935912a3cf97f5a31b39330e357aa61
4
+ data.tar.gz: f99cb0a632963344367f906285cc572b913932a1
5
5
  SHA512:
6
- metadata.gz: dc2e5f3b692f3881884296fea5495bfd7da4986ff992552d4bb84eafd789495b2985c3dbac6f0f4bb0d232fdcd1333ad8540bb8c6d474a633aa110d8c13b65bc
7
- data.tar.gz: 641b94a27502ff6263a13f5451970a92d5202897c4a3b8b2430e812db9e5403865396f3f6d51d2cf1729fce791e8693bf12371e9a90beb5b0e8e507eafaba74a
6
+ metadata.gz: 796bdd29576ca722747c2b2508571f6ab60197741e1dbf91532f4f6cdcbcfcc478e81d3ffb41e72345a22d5319eb9e066879144b6eaf7624bd0dd6765223d5aa
7
+ data.tar.gz: 5b0a456b2657f7a33823b98b864821ab8845296e63d459d661cce67d7d2b2a296208cb7097e34209bd4063510c79dc9f3906fbe8cd7ad7bce6265e1de7faca11
data/.travis.yml CHANGED
@@ -2,5 +2,4 @@ language: ruby
2
2
  rvm:
3
3
  - 2.2.1
4
4
  - 2.0.0
5
- - rbx-2.5.2
6
5
  - jruby-19mode
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 calling `super` appropriately in subclasses or initializing private data as necessary.
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
- pattr_initalize :name, :price
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
- rattr_initalize :book_name, :publisher_backend
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
- `rake`
403
+ rake
354
404
 
355
405
  Or to see warnings (try not to have any):
356
406
 
357
- `RUBYOPT=-w rake`
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
@@ -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::ModuleMethods
13
+ self::Mixin
13
14
  end
14
15
 
15
- # Separate module for `include`ing so that mixing in the methods doesn't also mix in constants:
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 ModuleMethods
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
- arg_names = names.last.is_a?(Array) ? names.pop : []
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
@@ -1,3 +1,3 @@
1
1
  module AttrExtras
2
- VERSION = "4.4.0"
2
+ VERSION = "4.5.0"
3
3
  end
data/script/test CHANGED
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Script used to have one way to run single tests in any project,
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
- # Test unit does not support line numbers :(
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 attr_private_initializer" do
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 attr_reader_initializer" do
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
@@ -37,7 +37,7 @@ describe Object, ".vattr_initialize" do
37
37
  called.must_equal true
38
38
  end
39
39
 
40
- it "accepts the alias attr_value_initializer" do
40
+ it "accepts the alias attr_value_initialize" do
41
41
  klass = Class.new do
42
42
  attr_value_initialize :foo, :bar
43
43
  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.0
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: 2015-03-08 00:00:00.000000000 Z
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