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 +7 -0
- data/README.md +192 -34
- data/lib/rlet/functional.rb +33 -0
- data/lib/rlet/lazy_options.rb +31 -0
- metadata +15 -15
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
18
|
+
gem install rlet
|
19
19
|
|
20
20
|
Or from bundler
|
21
21
|
|
22
|
-
|
22
|
+
gem 'rlet'
|
23
23
|
|
24
24
|
|
25
|
-
USAGE
|
26
|
-
====
|
25
|
+
## USAGE
|
27
26
|
|
28
|
-
|
27
|
+
### Let and Concern
|
29
28
|
|
30
|
-
|
29
|
+
The gems contain two modules, Let and Concern. You can use them like so:
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
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:
|
11
|
+
date: 2015-02-27 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
|
-
description:
|
13
|
+
description: Use rspec's let() outside of rspec with concerns and functional operators
|
15
14
|
email:
|
16
|
-
-
|
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:
|
46
|
+
rubygems_version: 2.2.2
|
47
47
|
signing_key:
|
48
|
-
specification_version:
|
49
|
-
summary:
|
48
|
+
specification_version: 4
|
49
|
+
summary: Lazy-eval and functional helpers
|
50
50
|
test_files: []
|