uber 0.0.8 → 0.0.9

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: 0665bfd37394ce176ce0d33f2c1d1f55f32dfa70
4
- data.tar.gz: 9a7bf2915ff6dd350d8d99c92c6a4b4afb9b6510
3
+ metadata.gz: 496f58fb856e20541ca2984b42e5ff34d6e5ce8d
4
+ data.tar.gz: 4344bb9b85e4e8ebaa198b1b532045b01cb6ebd9
5
5
  SHA512:
6
- metadata.gz: b5dc8ce07c0dc65cf1f818294f785f6c6bba0849a4ddf45152a379747ecbc3c981d895a6a6e9f0e8964eecd972234dc1838cbcb27b15f12f25bc12f44268dfbf
7
- data.tar.gz: d2dec91003d742e658c4c53350430f3793d3cf2edd43f4ae7644aeb6e12e9cab68c584bbcc4c7b9352feb6e970789fc4ce1ff8699347bf20ed353d825d2c3990
6
+ metadata.gz: 5adad36ffeacd88e2b0e66aeec0d99eb4f7b51baa8bfaeef89045d23bfbf6adcb70c7d6a94f0fbdecb1fe7a9137b15c07775a9ebdaf9cc9e430119c9fda76c6f
7
+ data.tar.gz: 78c7dbe731c85b2d8150e020b5d5afeda6bb9cf247d9706cc9fd39c06aad16c7da9cdb4b877479534daed35cbb3cba5f46bcecbc018aacac1daf82a97dded431
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.0.9
2
+
3
+ * Add `Uber::Builder`.
4
+
1
5
  # 0.0.8
2
6
 
3
7
  * Add `Uber::Delegates` that provides delegation that can be overridden and called with `super`.
data/README.md CHANGED
@@ -6,7 +6,9 @@ _Gem-authoring tools like class method inheritance in modules, dynamic options a
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'uber'
9
+ ```ruby
10
+ gem 'uber'
11
+ ```
10
12
 
11
13
  Ready?
12
14
 
@@ -190,34 +192,74 @@ song.title #=> "helloween!"
190
192
 
191
193
  Note how `#title` calls the original title and then downcases the string.
192
194
 
195
+
196
+ # Builder
197
+
198
+ When included, `Builder` allows to add builder instructions on the class level. These can then be evaluated when instantiating
199
+ the class to conditionally build (sub-)classes based on the incoming parameters.
200
+
201
+ ```ruby
202
+ class Listener
203
+ include Uber::Builder
204
+
205
+ builds do |params|
206
+ SignedIn if params[:current_user]
207
+ end
208
+ end
209
+
210
+ class SignedIn
211
+ end
212
+ ```
213
+
214
+ The class then has to use the builder to compute a class name using the build blocks you defined.
215
+
216
+ ```ruby
217
+ class Listener
218
+ def self.build(params)
219
+ class_builder.call(params).
220
+ new(params)
221
+ end
222
+ end
223
+ ```
224
+
225
+ As you can see, it's still up to you to _instantiate_ the object, the builder only helps you computing the concrete class.
226
+
227
+ ```ruby
228
+ Listener.build({}) #=> Listener
229
+ Listener.build({current_user: @current_user}) #=> SignedIn
230
+ ```
231
+
232
+ This pattern is used in [Cells](https://github.com/apotonick/cells), [Trailblazer](https://github.com/apotonick/trailblazer) and soon Reform and Representable/Roar, too.
233
+
234
+
193
235
  # Version
194
236
 
195
237
  Writing gems against other gems often involves checking for versions and loading appropriate version strategies - e.g. _"is Rails >= 4.0?"_. Uber gives you `Version` for easy, semantic version deciders.
196
238
 
197
239
  ```ruby
198
- version = Uber::Version.new("1.2.3")
240
+ version = Uber::Version.new("1.2.3")
199
241
  ```
200
242
 
201
243
  The API currently gives you `#>=` and `#~`.
202
244
 
203
245
  ```ruby
204
- version >= "1.1" #=> true
205
- version >= "1.3" #=> false
246
+ version >= "1.1" #=> true
247
+ version >= "1.3" #=> false
206
248
  ```
207
249
 
208
250
  The `~` method does a semantic check (currently on major and minor level, only).
209
251
 
210
252
  ```ruby
211
- version.~ "1.1" #=> false
212
- version.~ "1.2" #=> true
213
- version.~ "1.3" #=> false
253
+ version.~ "1.1" #=> false
254
+ version.~ "1.2" #=> true
255
+ version.~ "1.3" #=> false
214
256
  ```
215
257
 
216
258
  Accepting a list of versions, it makes it simple to check for multiple minor versions.
217
259
 
218
260
  ```ruby
219
- version.~ "1.1", "1.0" #=> false
220
- version.~ "1.1", "1.2" #=> true
261
+ version.~ "1.1", "1.0" #=> false
262
+ version.~ "1.1", "1.2" #=> true
221
263
  ```
222
264
 
223
265
 
@@ -225,10 +267,10 @@ Accepting a list of versions, it makes it simple to check for multiple minor ver
225
267
 
226
268
  (Please don't read this!)
227
269
 
228
- * You can enforce treating values as dynamic (or not): `Uber::Options::Value.new("time_to_live", dynamic: true)` will always run `#time_to_live` as an instance method on the context, even thou it is not a symbol.
270
+ * You can enforce treating values as dynamic (or not): `Uber::Options::Value.new("time_to_live", dynamic: true)` will always run `#time_to_live` as an instance method on the context, even though it is not a symbol.
229
271
 
230
272
  # License
231
273
 
232
274
  Copyright (c) 2014 by Nick Sutterer <apotonick@gmail.com>
233
275
 
234
- Roar is released under the [MIT License](http://www.opensource.org/licenses/MIT).
276
+ Roar is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,90 @@
1
+ require 'uber/inheritable_attr'
2
+
3
+ module Uber
4
+ # When included, allows to add builder on the class level.
5
+ #
6
+ # class Operation
7
+ # include Uber::Builder
8
+ #
9
+ # builds do |params|
10
+ # SignedIn if params[:current_user]
11
+ # end
12
+ #
13
+ # class SignedIn
14
+ # end
15
+ #
16
+ # The class then has to call the builder to compute a class name using the build blocks you defined.
17
+ #
18
+ # def self.build(params)
19
+ # class_builder.call(params).
20
+ # new(params)
21
+ # end
22
+ module Builder
23
+ def self.included(base)
24
+ base.extend(ClassMethods)
25
+ base.extend(InheritableAttr)
26
+ base.inheritable_attr :builders
27
+ base.builders = []
28
+ end
29
+
30
+ class Constant
31
+ def initialize(constant) # TODO: evaluate usage of builders and implement using Uber::Options::Value.
32
+ @constant = constant
33
+ @builders = @constant.builders # only dependency, must be a Cell::Base subclass.
34
+ end
35
+
36
+ def call(*args)
37
+ build_class_for(*args)
38
+ end
39
+
40
+ private
41
+ def build_class_for(*args)
42
+ @builders.each do |blk|
43
+ klass = run_builder_block(blk, *args) and return klass
44
+ end
45
+ @constant
46
+ end
47
+
48
+ def run_builder_block(block, *args)
49
+ block.call(*args)
50
+ end
51
+ end
52
+
53
+ module ClassMethods
54
+ # Adds a builder to the cell class. Builders are used in #cell to find out the concrete
55
+ # class for rendering. This is helpful if you frequently want to render subclasses according
56
+ # to different circumstances (e.g. login situations) and you don't want to place these deciders in
57
+ # your view code.
58
+ #
59
+ # Passes the model and options from #cell into the block.
60
+ #
61
+ # Multiple build blocks are ORed, if no builder matches the building cell is used.
62
+ #
63
+ # Example:
64
+ #
65
+ # Consider two different user box cells in your app.
66
+ #
67
+ # class AuthorizedUserBox < UserInfoBox
68
+ # end
69
+ #
70
+ # class AdminUserBox < UserInfoBox
71
+ # end
72
+ #
73
+ # Now you don't want to have deciders all over your views - use a declarative builder.
74
+ #
75
+ # UserInfoBox.build do |model, options|
76
+ # AuthorizedUserBox if options[:is_signed_in]
77
+ # AdminUserBox if model.admin?
78
+ # end
79
+ #
80
+ # In your view #cell will instantiate the right cell for you now.
81
+ def builds(&block)
82
+ builders << block
83
+ end
84
+
85
+ def class_builder
86
+ @class_builder ||= Constant.new(self)
87
+ end
88
+ end # ClassMethods
89
+ end
90
+ end
@@ -1,3 +1,3 @@
1
1
  module Uber
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+ require "uber/builder"
3
+
4
+ class BuilderTest < MiniTest::Spec
5
+ Evergreen = Struct.new(:title)
6
+ Hit = Struct.new(:title)
7
+
8
+ class Song
9
+ include Uber::Builder
10
+
11
+ builds do |options|
12
+ if options[:evergreen]
13
+ Evergreen
14
+ elsif options[:hit]
15
+ Hit
16
+ end
17
+ end
18
+
19
+ def self.build(options)
20
+ class_builder.call(options).new
21
+ end
22
+ end
23
+
24
+ # building class if no block matches
25
+ it { Song.build({}).must_be_instance_of Song }
26
+
27
+ it { Song.build({evergreen: true}).must_be_instance_of Evergreen }
28
+ it { Song.build({hit: true}).must_be_instance_of Hit }
29
+
30
+ # test chained builds.
31
+ class Track
32
+ include Uber::Builder
33
+
34
+ builds do |options|
35
+ Evergreen if options[:evergreen]
36
+ end
37
+
38
+ builds do |options|
39
+ Hit if options[:hit]
40
+ end
41
+
42
+ def self.build(options)
43
+ class_builder.call(options).new
44
+ end
45
+ end
46
+
47
+ it { Track.build({}).must_be_instance_of Track }
48
+ it { Track.build({evergreen: true}).must_be_instance_of Evergreen }
49
+ it { Track.build({hit: true}).must_be_instance_of Hit }
50
+
51
+
52
+ # test inheritance.
53
+ class Play < Song
54
+ end
55
+
56
+ it { Play.build({}).must_be_instance_of Play }
57
+ it { Play.build({evergreen: true}).must_be_instance_of Evergreen }
58
+ it { Play.build({hit: true}).must_be_instance_of Hit }
59
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-01 00:00:00.000000000 Z
11
+ date: 2014-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -52,12 +52,14 @@ files:
52
52
  - README.md
53
53
  - Rakefile
54
54
  - lib/uber.rb
55
+ - lib/uber/builder.rb
55
56
  - lib/uber/callable.rb
56
57
  - lib/uber/delegates.rb
57
58
  - lib/uber/inheritable_attr.rb
58
59
  - lib/uber/options.rb
59
60
  - lib/uber/uber_version.rb
60
61
  - lib/uber/version.rb
62
+ - test/builder_test.rb
61
63
  - test/delegates_test.rb
62
64
  - test/inheritable_attr_test.rb
63
65
  - test/inheritance_test.rb
@@ -92,6 +94,7 @@ specification_version: 4
92
94
  summary: Gem-authoring tools like class method inheritance in modules, dynamic options
93
95
  and more.
94
96
  test_files:
97
+ - test/builder_test.rb
95
98
  - test/delegates_test.rb
96
99
  - test/inheritable_attr_test.rb
97
100
  - test/inheritance_test.rb