beethoven 0.0.1 → 0.0.2

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: c66a2988156ddaabcb7d6e6791dad2a05e40473f
4
- data.tar.gz: c1a3b6736a70a2f716525ddf4ae7be912537e336
3
+ metadata.gz: bdf26fc9c7904a96681b438f0ea47a2061eea493
4
+ data.tar.gz: 3f5d73b121875564e705d8685c0cbad45db42cd8
5
5
  SHA512:
6
- metadata.gz: b7fc5cf70c12768bd8023185d3d37c8eb523fb6d9a04bdc0cc0755020796968a2d14578d63c054f1dc89bd9d9d6c7efd6f34c4e0bd2f794e4c8a5a787f2cc0d0
7
- data.tar.gz: 1d1124e69a4054c80732671657de6208dcb0e657cec21bafadb4a189c9910610eb5af209e1fa8c52712481b6c8758ed4d1a7c142f6f37762b1a59c82656ccc79
6
+ metadata.gz: f5b044385e4b14c01511ee53286ff51839c5a949e10b04e090dafd6dfc7702bf14f2b5b1ac5573ed8bcc58f0a1755aef5d27dcc1a4e5ee7f4f9b8a940570e770
7
+ data.tar.gz: 88b3693bf215390c9b9c74524e5d6b93eaa74a4b67fa9a0809b3dfd36bb45af746ebdd09e0b53cf995125043b3b936011a514583574e3452dbe9f89b152bd75d
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ beethoven
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.2
data/README.md CHANGED
@@ -1,6 +1,117 @@
1
1
  # Beethoven
2
2
 
3
- TODO: Write a gem description
3
+ Composition is an incredibly useful technique in functional programming.
4
+ I have been missing that in my development with Ruby, so I set out to implement it here.
5
+
6
+ In Haskell, you can write a function like:
7
+
8
+ ```haskell
9
+ -- f is a function that takes a value of type a
10
+ -- and returns a value of type b
11
+ f :: a -> b
12
+ ```
13
+
14
+ We need some analogy with Ruby concepts.
15
+ It doesn't appear to be methods, messages, or objects.
16
+ Classes, however, seem to do it nicely.
17
+
18
+ 1. Replace the arrow with `new`
19
+ 2. `a` is the *interface* or *duck* that fits the single parameter of the class.
20
+ 3. `b` is the interface/duck that fits the object produced by new.
21
+
22
+ So, we might express a class `F` that implements message `b` and expects an object responding to `a` as:
23
+
24
+ ```ruby
25
+ class F
26
+ attr_reader :b
27
+
28
+ def initialize(x)
29
+ @b = x.a
30
+ end
31
+ end
32
+ ```
33
+
34
+ Next up, we want some class that implements the duck that `F` expects.
35
+
36
+ ```ruby
37
+ class G
38
+ attr_reader :a
39
+
40
+ def initialize(x)
41
+ @a = x
42
+ end
43
+ end
44
+
45
+ G.new(5).a
46
+ # => 5
47
+
48
+ F.new(G.new(5)).b
49
+ # => 5
50
+ ```
51
+
52
+ This is class composition. But really, it'd be a lot nicer if we could write:
53
+
54
+ ```ruby
55
+ (F * G).new(5).b
56
+ # => 5
57
+ ```
58
+
59
+ Or, perhaps you prefer the bash-like pipe operator and reading your compositions from left to right.
60
+ No problem:
61
+
62
+ ```ruby
63
+ (G | F).new(5).b
64
+ # => 5
65
+ ```
66
+
67
+ Naturally, this is quite a bit more interesting when your classes do something other than simply returning the value they were given.
68
+ In this example, the classes expect a parameter that duck-types `value`.
69
+
70
+ ```ruby
71
+ class Add5
72
+ def initialize(x)
73
+ @value = x.value
74
+ end
75
+
76
+ def value
77
+ @value + 5
78
+ end
79
+ end
80
+
81
+ class Multiply10
82
+ def initialize(x)
83
+ @value = x.value
84
+ end
85
+
86
+ def value
87
+ @value * 10
88
+ end
89
+ end
90
+
91
+ class Lift
92
+ attr_reader :value
93
+
94
+ def initialize(x)
95
+ @value = x
96
+ end
97
+ end
98
+
99
+ (Add5 * Multiply10 * Lift).new(7).value
100
+ #=> 75
101
+
102
+ (Lift | Multiply10 | Add5).new(4).value
103
+ #=> 45
104
+ ```
105
+
106
+ If you'd prefer to compose classes directly, use `Beethoven::Composer`:
107
+
108
+ ```ruby
109
+ Mul10Add5 = Beethoven::Composer.new(Lift, Multiply10, Add5)
110
+ Mul10Add5.new(5).value
111
+ #=> 55
112
+ ```
113
+
114
+ A more practical example is presented [here](https://gist.github.com/parsonsmatt/c1abbb830b6976566198)
4
115
 
5
116
  ## Installation
6
117
 
@@ -18,10 +129,6 @@ Or install it yourself as:
18
129
 
19
130
  $ gem install beethoven
20
131
 
21
- ## Usage
22
-
23
- TODO: Write usage instructions here
24
-
25
132
  ## Contributing
26
133
 
27
134
  1. Fork it ( https://github.com/[my-github-username]/beethoven/fork )
@@ -0,0 +1,11 @@
1
+ module Beethoven
2
+ module Composable
3
+ def *(other)
4
+ new(other, self)
5
+ end
6
+
7
+ def |(other)
8
+ new(self, other)
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module Beethoven
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beethoven
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Parsons
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-28 00:00:00.000000000 Z
11
+ date: 2015-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -106,6 +106,8 @@ extra_rdoc_files: []
106
106
  files:
107
107
  - ".gitignore"
108
108
  - ".rspec"
109
+ - ".ruby-gemset"
110
+ - ".ruby-version"
109
111
  - Gemfile
110
112
  - Guardfile
111
113
  - LICENSE.txt
@@ -114,6 +116,7 @@ files:
114
116
  - beethoven.gemspec
115
117
  - lib/beethoven.rb
116
118
  - lib/beethoven/class.rb
119
+ - lib/beethoven/composable.rb
117
120
  - lib/beethoven/composer.rb
118
121
  - lib/beethoven/version.rb
119
122
  - spec/beethoven/composer_spec.rb
@@ -140,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
143
  version: '0'
141
144
  requirements: []
142
145
  rubyforge_project:
143
- rubygems_version: 2.4.5
146
+ rubygems_version: 2.4.6
144
147
  signing_key:
145
148
  specification_version: 4
146
149
  summary: Make it a bit easier to compose classes in Ruby