rlet 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []