funkify 0.0.2 → 0.0.3

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: d5d368db1d50577c1cf79227015a65bfa6c89d02
4
- data.tar.gz: 819c4d262056e8c8c2fbd4e37eeb3d822681e4f1
3
+ metadata.gz: b1509b7e4e421ff184a3ddebf8bae52b54063883
4
+ data.tar.gz: 30e1768e67a4a65de187b0035050c795fa572e61
5
5
  SHA512:
6
- metadata.gz: e1c249b9939eabca11d0221377aff41e2c59951c4980ab6e54e30f5ca1561bc0117c949429c43ade6a5de0a32a64651759eda7915c7857f9ab26466f5003a5f8
7
- data.tar.gz: 5948d58b24e0c4deaf5a397f4daf672531263b952aef994400f12ac775a5f41a2284996c39b8795321203f3e9a1bb5d02a9bf35656f22d77785d8c44d148c6dc
6
+ metadata.gz: d0ba7e0c32a65562b351b001264506ed55c13980382c25169dd76839cc23feb8138df7715aaf0cc9b8e000fe3cb56277bbc6684a3f2674f9e0263bf121594d58
7
+ data.tar.gz: e22735ce17f3f5e11ef60952c176d9d07ce1cb71f99370043035c0314e9998af8ba6b31ebf0e7f55760651713cba23dac33986947addedd82e1c05e77cd518c1
data/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  _Haskell-style partial application and composition for Ruby methods_
4
4
 
5
-
6
5
  "In computer science, partial application refers to the process of
7
6
  fixing a number of arguments to a function, producing another function of smaller arity."
8
7
  --[Wikipedia](http://en.wikipedia.org/wiki/Partial_application)
9
8
 
10
- [Partial application in haskell](http://www.haskell.org/haskellwiki/Partial_application)<br>
11
- [Function composition in haskell](http://www.haskell.org/haskellwiki/Function_composition)
9
+ [Curring in Haskell](http://www.haskell.org/haskellwiki/Currying)<br>
10
+ [Partial application in Haskell](http://www.haskell.org/haskellwiki/Partial_application)<br>
11
+ [Function composition in Haskell](http://www.haskell.org/haskellwiki/Function_composition)
12
12
 
13
13
 
14
14
  ## Usage
@@ -38,6 +38,8 @@ class MyFunkyClass
38
38
  end
39
39
  ```
40
40
 
41
+ ### Partial application and currying
42
+
41
43
  When a method supports autocurrying it can still be invoked normally (if all parameters are provided) however if less than the required number are given a `Proc` is returned
42
44
  with the given parameters partially applied:
43
45
 
@@ -49,18 +51,29 @@ add_1 = funky.add(1) #=> The `1` is partially applied and a `Proc` is returned
49
51
  add_1.(2) #=> We invoke that `Proc` with the remaining argument and the final result (`3`) is returned.
50
52
  ```
51
53
 
52
- We can also compose methods using `*`:
54
+ ### Function composition
55
+
56
+ We compose methods using the `*` and `|` operators.
53
57
 
58
+ `*` composes right to left, this is the standard way to compose functions found in languages like Haskell:
54
59
  ```ruby
55
- add_1_and_multiply_by_5 = funky.mult(5) * funky.add(1)
56
- add_1_and_multiply_by_5.(10) #=> 55
60
+ (mult(5) * add(1)).(10) #=> 55
57
61
 
58
- # We can even further compose the above with another method:
62
+ # We can further compose the above with another method:
63
+ (negate * mult(5) * add(1)).(10) #=> -55
64
+ ```
59
65
 
60
- (funky.negate * add_1_and_multiply_by_5).(10) #=> -55
66
+ `|` composes left to right, like a shell pipeline:
67
+ ```ruby
68
+ (mult(5) | add(1) | negate).(3) #=> -16
61
69
  ```
62
70
 
63
- Other examples:
71
+ As a cute bonus, we can inject values from the left into a pipeline with the `pass` method ([see more](http://showterm.io/47f46234281cf2c25f44a#fast)):
72
+ ```ruby
73
+ pass(3) | (mult(5) | add(1) | negate) #=> -16
74
+ ```
75
+
76
+ #### Other examples:
64
77
 
65
78
  Add 10 to every item in an Enumerable:
66
79
 
@@ -87,6 +100,10 @@ And then execute:
87
100
  Or install it yourself as:
88
101
 
89
102
  $ gem install funkify
103
+
104
+ ## Dedication
105
+
106
+ This library was inspired in part by stimulating conversations with [epitron](https://github.com/epitron) on Freenode.
90
107
 
91
108
  ## Contributing
92
109
 
data/Rakefile CHANGED
@@ -8,6 +8,34 @@ def run_specs paths
8
8
  exec "bacon -Ispec -rubygems #{quiet} #{paths.join ' '}"
9
9
  end
10
10
 
11
+ desc "run tests"
11
12
  task :test do
12
13
  run_specs Dir['spec/**/*_spec.rb'].shuffle!
13
14
  end
15
+
16
+ desc "run pry with the development version of funkify loaded"
17
+ task :pry do
18
+ sh "pry -I./lib -r funkify"
19
+ end
20
+
21
+ desc "remove all gems"
22
+ task :rm_gems do
23
+ sh "rm *.gem" rescue nil
24
+ end
25
+
26
+ desc "build the gem"
27
+ task :gem => :rm_gems do
28
+ sh "gem build funkify.gemspec"
29
+ end
30
+
31
+ desc "display the current version"
32
+ task :version do
33
+ puts Funkify::VERSION
34
+ end
35
+
36
+ desc "build and push latest gems"
37
+ task :pushgem => :gem do
38
+ Dir["*.gem"].each do |gemfile|
39
+ sh "gem push funkify-#{Funkify::VERSION}.gem"
40
+ end
41
+ end
@@ -9,6 +9,14 @@ module Funkify
9
9
  def *(other)
10
10
  Funkify.compose(self, other)
11
11
  end
12
+
13
+ def |(other)
14
+ if arity.zero?
15
+ other.(*self.())
16
+ else
17
+ Funkify.compose(other, self)
18
+ end
19
+ end
12
20
  end
13
21
 
14
22
  module_function
@@ -22,6 +30,11 @@ module Funkify
22
30
  end
23
31
  end
24
32
 
33
+ def pass(*xs)
34
+ -> { xs }
35
+ end
36
+ public :pass
37
+
25
38
  def compose(*args)
26
39
  head, *tail = args
27
40
  head = _procify(head)
@@ -41,22 +54,22 @@ module Funkify
41
54
  end
42
55
  end
43
56
 
44
- module ClassMethods
45
- def auto_curry(*names)
46
- if names.empty?
47
- in_use = nil
48
- define_singleton_method(:method_added) do |name|
49
- return if in_use
50
- in_use = true
51
- auto_curry name
52
- in_use = false
53
- end
54
- return
55
- end
57
+ def self.auto_curry_all_methods(receiver)
58
+ in_use = nil
59
+ receiver.define_singleton_method(:method_added) do |name|
60
+ return if in_use
61
+ in_use = true
62
+ receiver.auto_curry name
63
+ in_use = false
64
+ end
65
+ end
56
66
 
57
- names.each do |name|
58
- m = instance_method(name)
59
- curried_method = nil
67
+ def self.auto_curry_some_methods(names, receiver)
68
+ names.each do |name|
69
+ m = receiver.instance_method(name)
70
+ curried_method = nil
71
+
72
+ receiver.class_eval do
60
73
  define_method(name) do |*args|
61
74
  curried_method ||= m.bind(self).to_proc.curry
62
75
  curried_method[*args]
@@ -64,4 +77,21 @@ module Funkify
64
77
  end
65
78
  end
66
79
  end
80
+
81
+ module ClassMethods
82
+ def auto_curry(*names)
83
+ if names.empty?
84
+ Funkify.auto_curry_all_methods(self)
85
+ else
86
+ Funkify.auto_curry_some_methods(names, self)
87
+ end
88
+ end
89
+
90
+ def point_free(&block)
91
+ -> (*args) do
92
+ b = instance_exec(&block).curry
93
+ args.empty? ? b : b[*args]
94
+ end
95
+ end
96
+ end
67
97
  end
@@ -1,3 +1,3 @@
1
1
  module Funkify
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -105,20 +105,50 @@ describe Funkify do
105
105
  end.new
106
106
  end
107
107
 
108
- it 'returns a new Proc when composing methods' do
109
- (@c.negate * @c.plus_1).is_a?(Proc).should == true
110
- end
108
+ describe "normal composition" do
109
+ it 'returns a new Proc when composing methods' do
110
+ (@c.negate * @c.plus_1).is_a?(Proc).should == true
111
+ end
112
+
113
+ it 'invokes composed methods in the correct order (right-to-left)' do
114
+ (@c.negate * @c.plus_1).(5).should == -6
115
+ end
111
116
 
112
- it 'invokes composed methods in the correct order (right-to-left)' do
113
- (@c.negate * @c.plus_1).(5).should == -6
117
+ it 'can compose partially applied methods' do
118
+ (@c.add(5) * @c.mult(2)).(5).should == 15
119
+ end
120
+
121
+ it 'can compose multiple methods' do
122
+ (@c.negate * @c.add(5) * @c.mult(5)).(5).should == -30
123
+ end
114
124
  end
115
125
 
116
- it 'can compose partially applied methods' do
117
- (@c.add(5) * @c.mult(2)).(5).should == 15
126
+ describe "reverse composition" do
127
+ it 'returns a new Proc when composing methods' do
128
+ (@c.negate | @c.plus_1).is_a?(Proc).should == true
129
+ end
130
+
131
+ it 'invokes reverse-composed methods in the correct order (left-to-right)' do
132
+ (@c.negate | @c.plus_1).(5).should == -4
133
+ end
134
+
135
+ it 'can reverse-compose partially applied methods' do
136
+ (@c.add(5) | @c.mult(2)).(5).should == 20
137
+ end
138
+
139
+ it 'can reverse-compose multiple methods' do
140
+ (@c.negate | @c.add(5) | @c.mult(5)).(5).should == 0
141
+ end
118
142
  end
119
143
 
120
- it 'can compose multiple methods' do
121
- (@c.negate * @c.add(5) * @c.mult(5)).(5).should == -30
144
+ describe "pass method" do
145
+ it 'passes values into a reverse-composition stream' do
146
+ (@c.pass(5) | ( @c.add(5) | @c.mult(5))).should == 50
147
+ end
148
+
149
+ it 'passes values into a normal-composition stream' do
150
+ (@c.pass(5) | ( @c.add(5) * @c.mult(5))).should == 30
151
+ end
122
152
  end
123
153
  end
124
154
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: funkify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mair
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-11 00:00:00.000000000 Z
11
+ date: 2013-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler