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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f5eb6bc7db51a9a4fe42e38ae87a7baab814343
4
- data.tar.gz: 605da301958aa87e8153c4b82f5f6eb762769869
3
+ metadata.gz: e2ba1c064128e5483f807aa5367fa65bdd302598
4
+ data.tar.gz: 18024be7545a1a587b2d7c86a743b3f20c99e62a
5
5
  SHA512:
6
- metadata.gz: 09b1b88225c844faae7b42611ceb4acf093c9c79ce567eb9fdc65640947722789828260910ddf82989e1ef24c047fd462265042ac16ce3132a683621ec9854a9
7
- data.tar.gz: ccaa25e72e8457fe368cb5ead1d313fadab809a955cea21030587319e59c02b427b7a0ac09d58c4f8cbeaec8bf5a4198e2d8efaa366c1eead26d27a1f76ad22e
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 split
38
- Not implemented
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:
@@ -1,35 +1,27 @@
1
1
  require "arrows/version"
2
2
 
3
3
  module Arrows
4
- class Either
5
- attr_accessor :payload
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[*either.payload] : g[*either.payload]
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 |*args|
22
- [f[*args.first], g[*args.last]]
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 { |*args| [f[*args], g[*args]] }
18
+ Arrows::Proc.new { |args| [f[args], g[args]] }
27
19
  end
28
20
  def compose(f,g)
29
- Arrows::Proc.new { |*args| g[*f[*args]] }
21
+ Arrows::Proc.new { |args| g[f[args]] }
30
22
  end
31
23
  def fmap(xs, f)
32
- Arrows::Proc.new { |*args| xs[*args].map { |*x| f[*x] } }
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 { |*args| x }
37
+ Arrows::Proc.new { |args| x }
46
38
  end
47
39
  def arrow_like?(x)
48
- proc_like?(x) && x.arity == -1
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 |*args|
55
- f[*args]
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
@@ -0,0 +1,10 @@
1
+ class Arrows::Either
2
+ attr_accessor :payload
3
+ def initialize(good_or_evil, payload)
4
+ @good = !!good_or_evil
5
+ @payload = payload
6
+ end
7
+ def good?
8
+ @good
9
+ end
10
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Arrows
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -42,7 +42,7 @@ RSpec.describe Arrows::Proc do
42
42
  end
43
43
  context 'arity' do
44
44
  let(:par) { times2 % plus3 }
45
- subject { par.call 1,2 }
45
+ subject { par.call [1,2] }
46
46
  specify { should eq [2, 5] }
47
47
  end
48
48
  context 'result' do
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.5
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