rlet 0.5.1 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8109f3f222f16dbf36e7da3292ed7987f00a5932
4
+ data.tar.gz: 17310f476fb99e9f82a8ce6147b63c2663908f80
5
+ SHA512:
6
+ metadata.gz: 9c15981e58772ccf331396163b264b1a1b6f1506ccc5f9c1d45a21a3c0e36636200879f519b12e2a81df18c9032a4fc080e01ad40fecc1164a4620680e3ce1e7
7
+ data.tar.gz: 91b670103ba95aad945548791632b239df8287cf2e4ecc24d155cc8f3561392188022bc3f526fdcb84e5524608b5ae2207465fabc5d9c6dc1222c69d42b0ccda
data/README.md CHANGED
@@ -1,54 +1,212 @@
1
- rlet
2
- ====
1
+ # rlet
3
2
 
4
- Ruby let(), class-based lexical scoping
3
+ This library contains a library for RSpec-style let() declartions for lazy evaluation,
4
+ concerns, and a few functional operators.
5
5
 
6
- Unlike ruby-let, or what is proposed here http://www.opensourcery.com/blog/zack-hobson/objectlet-ruby-0
7
- this does not actually mimic the let of functional programming. Instead, it controls scope idiomatic
8
- to Ruby -- "everything is an object".
6
+ Unlike ruby-let, or what is proposed here http://www.opensourcery.com/blog/zack-hobson/objectlet-ruby-0
7
+ this does not actually mimic the let of functional programming.
9
8
 
10
- Here, let() defines a method in the class. The values are memoized. This allows for both
9
+ Here, `let()` defines a method in the class. The values are memoized. This allows for both
11
10
  lazy-evaluation and class-based scoping.
12
11
 
13
- This is based on RSpec let(). Tutorials and documentation are forthcoming.
12
+ By defining methods for lazy evaluation and grouping them into concerns, you can create
13
+ mixins that can be shared across multiple objects. Lazy-eval lends itself to functional
14
+ programming, so a small refinment is made available for use.
14
15
 
15
- INSTALLING
16
- ====
16
+ ## INSTALLING
17
17
 
18
- gem install rlet
18
+ gem install rlet
19
19
 
20
20
  Or from bundler
21
21
 
22
- gem 'rlet'
22
+ gem 'rlet'
23
23
 
24
24
 
25
- USAGE
26
- ====
25
+ ## USAGE
27
26
 
28
- The gems contain two modules, Let and Concern. You can use them like so:
27
+ ### Let and Concern
29
28
 
30
- require 'rlet'
29
+ The gems contain two modules, Let and Concern. You can use them like so:
31
30
 
32
- class ContactsController
33
- include Let
34
- include RestfulResource
35
-
36
- let(:model) { Contact }
37
-
38
- def show
39
- respond_with resource
31
+ require 'rlet'
32
+
33
+ class ContactsController
34
+ include Let
35
+ include RestfulResource
36
+
37
+ let(:model) { Contact }
38
+
39
+ def show
40
+ respond_with resource
41
+ end
40
42
  end
41
- end
42
-
43
- module RestfulResource
44
- extend Concern
45
-
46
- included do
47
- let(:resource) { model.find(id) }
48
- let(:id) { params[:id]
43
+
44
+ module RestfulResource
45
+ extend Concern
46
+
47
+ included do
48
+ let(:resource) { model.find(id) }
49
+ let(:id) { params[:id] }
50
+ end
49
51
  end
50
- end
51
-
52
52
 
53
53
  Concern is embedded from ActiveSupport. If ActiveSupport::Concern is loaded, it will use that. This
54
54
  allows one to use concerns without having ActiveSupport as a dependency.
55
+
56
+ ### LazyOptions
57
+
58
+ One pattern that comes up is creating a class which takes an option as an initializer, and then
59
+ using `let()` to define values based on those options.
60
+
61
+ For example:
62
+
63
+ module Intentions
64
+ class Promise
65
+ include Let
66
+ extend Intentions::Concerns::Register
67
+
68
+ attr_reader :identifier, :promiser, :promisee, :body, :metadata
69
+
70
+ let(:identifier) { Digest::SHA2.new.update(to_digest.inspect).to_s }
71
+ let(:sign) { metadata[:sign] }
72
+ let(:scope) { metadata[:scope] }
73
+ let(:timestamp) { Time.now.utc }
74
+ let(:salt) { rand(100000) }
75
+
76
+ def initialize(_promiser, _promisee, _body, _metadata = {})
77
+ @promiser = _promiser.freeze
78
+ @promisee = _promisee.freeze
79
+ @body = _body.freeze
80
+ @metadata = _metadata.freeze
81
+ self
82
+ end
83
+
84
+ def to_h
85
+ to_digest.merge(identifier: identifier)
86
+ end
87
+
88
+ def to_digest
89
+ {
90
+ promiser: promiser,
91
+ promisee: promisee,
92
+ body: body,
93
+ metadata: metadata,
94
+ timestamp: timestamp,
95
+ salt: salt
96
+ }
97
+ end
98
+
99
+ end
100
+ end
101
+
102
+ We can refactor into:
103
+
104
+ module Intentions
105
+ class Promise
106
+ include Let
107
+ extend Intentions::Concerns::Register
108
+
109
+ attr_reader :options
110
+
111
+ let(:promiser) { options[:promiser] }
112
+ let(:promisee) { options[:promisee] }
113
+ let(:body) { options[:body] }
114
+ let(:metadata) { options[:metadata] }
115
+
116
+ let(:identifier) { Digest::SHA2.new.update(to_digest.inspect).to_s }
117
+ let(:sign) { metadata[:sign] }
118
+ let(:scope) { metadata[:scope] }
119
+ let(:timestamp) { Time.now.utc }
120
+ let(:salt) { rand(100000) }
121
+
122
+ def initialize(_options = {})
123
+ @options = _options
124
+ end
125
+
126
+ def to_h
127
+ to_digest.merge(identifier: identifier)
128
+ end
129
+
130
+ def to_digest
131
+ {
132
+ promiser: promiser,
133
+ promisee: promisee,
134
+ body: body,
135
+ metadata: metadata,
136
+ timestamp: timestamp,
137
+ salt: salt
138
+ }
139
+ end
140
+
141
+ end
142
+ end
143
+
144
+ This pattern occurs so frequently that `rlet` not includes a `LazyOptions` concern.
145
+
146
+ require 'rlet/lazy_options'
147
+ module Intentions
148
+ class Promise
149
+ include Let
150
+ include LazyOptions
151
+ extend Intentions::Concerns::Register
152
+
153
+ let(:promiser) { options[:promiser] }
154
+ let(:promisee) { options[:promisee] }
155
+ let(:body) { options[:body] }
156
+ let(:metadata) { options[:metadata] }
157
+
158
+ let(:identifier) { Digest::SHA2.new.update(to_digest.inspect).to_s }
159
+ let(:sign) { metadata[:sign] }
160
+ let(:scope) { metadata[:scope] }
161
+ let(:timestamp) { Time.now.utc }
162
+ let(:salt) { rand(100000) }
163
+
164
+ def to_h
165
+ to_digest.merge(identifier: identifier)
166
+ end
167
+
168
+ def to_digest
169
+ {
170
+ promiser: promiser,
171
+ promisee: promisee,
172
+ body: body,
173
+ metadata: metadata,
174
+ timestamp: timestamp,
175
+ salt: salt
176
+ }
177
+ end
178
+
179
+ end
180
+ end
181
+
182
+ ### Functional Operators
183
+
184
+ Lazy-eval lends itself well to functional patterns. However, Ruby doesn't include many
185
+ built-in operators for working with higher order functions. `rlet` includes a refinment (Ruby 2.0+)
186
+ that adds in some operators.
187
+
188
+ Currently, only two are supported: `|` which composes right, and `*` which composes left.
189
+
190
+ The best example is when working with Intermodal presenters:
191
+
192
+ require 'rlet/functional'
193
+
194
+ module SomeApi
195
+ module API
196
+ class V1_0 < Intermodal::API
197
+ using RLet::Functional
198
+
199
+ self.default_per_page = 25
200
+
201
+ map_data do
202
+ attribute = ->(field) { ->(r) { r.send(field) } }
203
+ helper = ->(_method) { ActionController::Base.helpers.method(_method) }
204
+
205
+ presentation_for :book do
206
+ presents :id
207
+ presents :price, with: attribute.(:price) | helper.(:number_to_currency)
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,33 @@
1
+ # This module requires refinements (Ruby 2.1+)
2
+ #
3
+ # To use this module, specify it with the using keyword:
4
+ #
5
+ # class StreamProcessor
6
+ # include Let
7
+ # using RLet::Functional
8
+ #
9
+ # let(:user) { User.create (minimum | with_photos).() }
10
+ # let(:minimum) { { username: 'user', password: 'password' } }
11
+ # let(:with_nick) { ->(x) { x.merge(nick: 'Breaker') } }
12
+ # end
13
+
14
+ module RLet
15
+ module Functional
16
+ module Compose
17
+ def *(other)
18
+ Proc.new { |x| call(other.call(x)) }
19
+ end
20
+ def |(other)
21
+ Proc.new { |x| other.call(call(x)) }
22
+ end
23
+ end
24
+
25
+ refine Proc do
26
+ include Compose
27
+ end
28
+
29
+ refine Method do
30
+ include Compose
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # Include this module when you want to have a hash initializer. This
2
+ # allows you to build let() definitions derived from what gets passed
3
+ # into the initializer
4
+ #
5
+ # For example:
6
+ #
7
+ # class Task
8
+ # include Let
9
+ # include RLet::LazyOptions
10
+ #
11
+ # let(:name) { options[:name] }
12
+ # end
13
+ #
14
+ # t = Task.new name: 'MyTask'
15
+ # t.name
16
+ # => 'MyTask'
17
+
18
+ module RLet
19
+ module LazyOptions
20
+ extend Concern
21
+
22
+ included do
23
+ attr_reader :options
24
+
25
+ def initialize(opts = {})
26
+ @options = opts
27
+ end
28
+ end
29
+
30
+ end
31
+ end
metadata CHANGED
@@ -1,50 +1,50 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rlet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
5
- prerelease:
4
+ version: 0.6.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ho-Sheng Hsiao
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-08-09 00:00:00.000000000Z
11
+ date: 2015-02-27 00:00:00.000000000 Z
13
12
  dependencies: []
14
- description: Class-based scoping with let(). Use rspec's let() outside of rspec
13
+ description: Use rspec's let() outside of rspec with concerns and functional operators
15
14
  email:
16
- - hosh@opscode.com
15
+ - talktohosh@gmail.com
17
16
  executables: []
18
17
  extensions: []
19
18
  extra_rdoc_files: []
20
19
  files:
21
- - lib/rlet/concern.rb
22
- - lib/rlet/let.rb
23
- - lib/rlet.rb
24
20
  - LICENSE.txt
25
21
  - README.md
22
+ - lib/rlet.rb
23
+ - lib/rlet/concern.rb
24
+ - lib/rlet/functional.rb
25
+ - lib/rlet/lazy_options.rb
26
+ - lib/rlet/let.rb
26
27
  homepage: http://github.com/hosh/rlet
27
28
  licenses: []
29
+ metadata: {}
28
30
  post_install_message:
29
31
  rdoc_options: []
30
32
  require_paths:
31
33
  - lib
32
34
  required_ruby_version: !ruby/object:Gem::Requirement
33
- none: false
34
35
  requirements:
35
- - - ! '>='
36
+ - - ">="
36
37
  - !ruby/object:Gem::Version
37
38
  version: '0'
38
39
  required_rubygems_version: !ruby/object:Gem::Requirement
39
- none: false
40
40
  requirements:
41
- - - ! '>='
41
+ - - ">="
42
42
  - !ruby/object:Gem::Version
43
43
  version: 1.3.6
44
44
  requirements: []
45
45
  rubyforge_project: rlet
46
- rubygems_version: 1.8.10
46
+ rubygems_version: 2.2.2
47
47
  signing_key:
48
- specification_version: 3
49
- summary: Class-based scoping with let()
48
+ specification_version: 4
49
+ summary: Lazy-eval and functional helpers
50
50
  test_files: []