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 +4 -4
- data/CHANGES.md +4 -0
- data/README.md +53 -11
- data/lib/uber/builder.rb +90 -0
- data/lib/uber/uber_version.rb +1 -1
- data/test/builder_test.rb +59 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 496f58fb856e20541ca2984b42e5ff34d6e5ce8d
|
4
|
+
data.tar.gz: 4344bb9b85e4e8ebaa198b1b532045b01cb6ebd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5adad36ffeacd88e2b0e66aeec0d99eb4f7b51baa8bfaeef89045d23bfbf6adcb70c7d6a94f0fbdecb1fe7a9137b15c07775a9ebdaf9cc9e430119c9fda76c6f
|
7
|
+
data.tar.gz: 78c7dbe731c85b2d8150e020b5d5afeda6bb9cf247d9706cc9fd39c06aad16c7da9cdb4b877479534daed35cbb3cba5f46bcecbc018aacac1daf82a97dded431
|
data/CHANGES.md
CHANGED
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
|
-
|
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
|
-
|
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
|
-
|
205
|
-
|
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
|
-
|
212
|
-
|
213
|
-
|
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
|
-
|
220
|
-
|
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
|
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).
|
data/lib/uber/builder.rb
ADDED
@@ -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
|
data/lib/uber/uber_version.rb
CHANGED
@@ -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.
|
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
|
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
|