funkify 0.0.2 → 0.0.3

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 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