arrows 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -2
- data/lib/arrows.rb +12 -46
- data/lib/arrows/either.rb +10 -0
- data/lib/arrows/proc.rb +26 -0
- data/lib/arrows/version.rb +1 -1
- data/spec/arrows/proc_spec.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2ba1c064128e5483f807aa5367fa65bdd302598
|
4
|
+
data.tar.gz: 18024be7545a1a587b2d7c86a743b3f20c99e62a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fafb6881ac9cafa72974919a52bb141c9ecb3fb33674ccc784609be69e32980fc0366acbfb889182798b66111298061bce72a3cc501673ca9b3ff366cd1ff718
|
7
|
+
data.tar.gz: ba107db1e9864f19086282c19a4fa51248743faad98f16735826c7a0e99ac82fda5ffd09afced6d94b41a4dbb88176fcb364c96d96db5bd54ce3f0f6cf182b16
|
data/README.md
CHANGED
@@ -34,8 +34,9 @@ x -> z
|
|
34
34
|
becomes
|
35
35
|
x -> [y,z]
|
36
36
|
|
37
|
-
### Arrow
|
38
|
-
|
37
|
+
### Arrow Fork
|
38
|
+
f ^ g produces a proc that takes in a Either, and if either is good, f is evaluated, if either is evil, g is evaluated
|
39
|
+
|
39
40
|
|
40
41
|
## Use Case
|
41
42
|
Suppose you're running rails (lol what else is there in ruby?) for some sort of ecommerce app and you have an OfferController that handles inputs from an user who is trying to make an offer on some listing you have. Your controller might look like this:
|
@@ -93,6 +94,59 @@ class OfferController < ApplicationController
|
|
93
94
|
end
|
94
95
|
```
|
95
96
|
That is, offer creation has been reduced back down to a process with distinct steps.
|
97
|
+
|
98
|
+
### Another Example
|
99
|
+
Here's an example directly from one of my other applications
|
100
|
+
```ruby
|
101
|
+
class Apiv1::Contacts::UpdateController < Apiv1::UsersController
|
102
|
+
before_filter :_enforce_correct_user
|
103
|
+
def update
|
104
|
+
_update_process.call
|
105
|
+
end
|
106
|
+
private
|
107
|
+
def _enforce_correct_user
|
108
|
+
unless current_user.admin? || current_user.contacts.include?(_contact)
|
109
|
+
render json: { message: "This isn't your listing" }, status: 401
|
110
|
+
end
|
111
|
+
end
|
112
|
+
def _update_process
|
113
|
+
_user_inputs >> _apply_changes >> _decide_validity >> (_update_valid_data_process ^ _render_failure)
|
114
|
+
end
|
115
|
+
def _update_valid_data_process
|
116
|
+
_save_changes >> _decide_primality >> (_make_primary ^ Arrows::ID) >> _render_success
|
117
|
+
end
|
118
|
+
def _user_inputs
|
119
|
+
Arrows.lift _contact
|
120
|
+
end
|
121
|
+
def _apply_changes
|
122
|
+
Arrows.lift -> (contact) { contact.tap { |p| p.assign_attributes _contact_params } }
|
123
|
+
end
|
124
|
+
def _decide_validity
|
125
|
+
Arrows.lift -> (contact) { contact.valid? ? Arrows.good(contact) : Arrows.evil(contact) }
|
126
|
+
end
|
127
|
+
def _decide_primality
|
128
|
+
Arrows.lift -> (contact) { _contact_params[:status] == "primary" ? Arrows.good(contact) : Arrows.evil(contact) }
|
129
|
+
end
|
130
|
+
def _render_success
|
131
|
+
Arrows.lift -> (contact) { render json: { contact: contact.to_ember_hash } }
|
132
|
+
end
|
133
|
+
def _save_changes
|
134
|
+
Arrows.lift -> (contact) { contact.tap(&:save!) }
|
135
|
+
end
|
136
|
+
def _make_primary
|
137
|
+
Arrows.lift -> (contact) { contact.tap &:make_primary! }
|
138
|
+
end
|
139
|
+
def _render_failure
|
140
|
+
Arrows.lift -> (contact) { render json: contact.errors.to_h, status: :expectation_failed }
|
141
|
+
end
|
142
|
+
def _contact
|
143
|
+
@contact ||= Apiv1::UserContact.find params[:id]
|
144
|
+
end
|
145
|
+
def _contact_params
|
146
|
+
@contact_params ||= params.require(:contact).permit(:name, :phone, :email, :address, :status)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
```
|
96
150
|
## Installation
|
97
151
|
|
98
152
|
Add this line to your application's Gemfile:
|
data/lib/arrows.rb
CHANGED
@@ -1,35 +1,27 @@
|
|
1
1
|
require "arrows/version"
|
2
2
|
|
3
3
|
module Arrows
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(good_or_evil, payload)
|
7
|
-
@good = !!good_or_evil
|
8
|
-
@payload = payload
|
9
|
-
end
|
10
|
-
def good?
|
11
|
-
@good
|
12
|
-
end
|
13
|
-
end
|
4
|
+
require 'arrows/either'
|
5
|
+
require 'arrows/proc'
|
14
6
|
class << self
|
15
7
|
def fork(f,g)
|
16
8
|
Arrows::Proc.new do |either|
|
17
|
-
either.good? ? f[
|
9
|
+
either.good? ? f[either.payload] : g[either.payload]
|
18
10
|
end
|
19
11
|
end
|
20
12
|
def concurrent(f,g)
|
21
|
-
Arrows::Proc.new do
|
22
|
-
[f[
|
13
|
+
Arrows::Proc.new do |args|
|
14
|
+
[f[args.first], g[args.last]]
|
23
15
|
end
|
24
16
|
end
|
25
17
|
def fanout(f,g)
|
26
|
-
Arrows::Proc.new {
|
18
|
+
Arrows::Proc.new { |args| [f[args], g[args]] }
|
27
19
|
end
|
28
20
|
def compose(f,g)
|
29
|
-
Arrows::Proc.new {
|
21
|
+
Arrows::Proc.new { |args| g[f[args]] }
|
30
22
|
end
|
31
23
|
def fmap(xs, f)
|
32
|
-
Arrows::Proc.new {
|
24
|
+
Arrows::Proc.new { |args| xs[args].map { |x| f[x] } }
|
33
25
|
end
|
34
26
|
def good(x)
|
35
27
|
return x if x.respond_to?(:good?) && x.respond_to?(:payload)
|
@@ -42,45 +34,19 @@ module Arrows
|
|
42
34
|
def lift(x)
|
43
35
|
return x if arrow_like? x
|
44
36
|
return wrap_proc x if proc_like? x
|
45
|
-
Arrows::Proc.new {
|
37
|
+
Arrows::Proc.new { |args| x }
|
46
38
|
end
|
47
39
|
def arrow_like?(x)
|
48
|
-
proc_like?(x) && x.arity ==
|
40
|
+
proc_like?(x) && x.arity == 1 && x.respond_to?(:>=) && x.respond_to?(:>>)
|
49
41
|
end
|
50
42
|
def proc_like?(x)
|
51
43
|
x.respond_to?(:call) && x.respond_to?(:arity)
|
52
44
|
end
|
53
45
|
def wrap_proc(f)
|
54
|
-
Arrows::Proc.new do
|
55
|
-
f[
|
46
|
+
Arrows::Proc.new do |args|
|
47
|
+
f[args]
|
56
48
|
end
|
57
49
|
end
|
58
50
|
end
|
59
|
-
class Proc < ::Proc
|
60
|
-
# applicative fmap
|
61
|
-
def >=(f)
|
62
|
-
Arrows.fmap self, Arrows.lift(f)
|
63
|
-
end
|
64
|
-
|
65
|
-
# standard composition
|
66
|
-
def >>(f)
|
67
|
-
Arrows.compose self, Arrows.lift(f)
|
68
|
-
end
|
69
|
-
|
70
|
-
# fanout composition
|
71
|
-
def /(f)
|
72
|
-
Arrows.fanout self, Arrows.lift(f)
|
73
|
-
end
|
74
|
-
|
75
|
-
# concurrent composition
|
76
|
-
def %(f)
|
77
|
-
Arrows.concurrent self, Arrows.lift(f)
|
78
|
-
end
|
79
|
-
|
80
|
-
# fork composition
|
81
|
-
def ^(f)
|
82
|
-
Arrows.fork self, f
|
83
|
-
end
|
84
|
-
end
|
85
51
|
ID = lift -> (x) { x }
|
86
52
|
end
|
data/lib/arrows/proc.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Arrows::Proc < Proc
|
2
|
+
# applicative fmap
|
3
|
+
def >=(f)
|
4
|
+
Arrows.fmap self, Arrows.lift(f)
|
5
|
+
end
|
6
|
+
|
7
|
+
# standard composition
|
8
|
+
def >>(f)
|
9
|
+
Arrows.compose self, Arrows.lift(f)
|
10
|
+
end
|
11
|
+
|
12
|
+
# fanout composition
|
13
|
+
def /(f)
|
14
|
+
Arrows.fanout self, Arrows.lift(f)
|
15
|
+
end
|
16
|
+
|
17
|
+
# concurrent composition
|
18
|
+
def %(f)
|
19
|
+
Arrows.concurrent self, Arrows.lift(f)
|
20
|
+
end
|
21
|
+
|
22
|
+
# fork composition
|
23
|
+
def ^(f)
|
24
|
+
Arrows.fork self, f
|
25
|
+
end
|
26
|
+
end
|
data/lib/arrows/version.rb
CHANGED
data/spec/arrows/proc_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arrows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Chen
|
@@ -81,6 +81,8 @@ files:
|
|
81
81
|
- Rakefile
|
82
82
|
- arrows.gemspec
|
83
83
|
- lib/arrows.rb
|
84
|
+
- lib/arrows/either.rb
|
85
|
+
- lib/arrows/proc.rb
|
84
86
|
- lib/arrows/version.rb
|
85
87
|
- spec/arrows/proc_spec.rb
|
86
88
|
- spec/spec_helper.rb
|