ruby-lambdas 0.3.0 → 0.4.0

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
  SHA256:
3
- metadata.gz: fdd09393827cb1cfa7166f4c9390c500b45cb6e374ea1e7fff85d6e8d1023444
4
- data.tar.gz: ea9faa37417a2abf246d9049e40f09247faacf1908550e84b7bb98d3b342f404
3
+ metadata.gz: b8d0f6978b6dddacda782f2d7451c3fca0da1c4403d7fa5cf4f048b028fad117
4
+ data.tar.gz: 0ecccceb696c038d2b0b0ad310ff5701343f4d39cffae56058d8d2abb3f8f48b
5
5
  SHA512:
6
- metadata.gz: 72b50b42fcebeb42306809114066e946783bc6bfd33e23eea1acd256adc70634de56de2d9fe83bbd0a63c1116733c2db13a3887fa9163352176d8643c05ef62f
7
- data.tar.gz: b06bea15c208280081a98fa62bb3d2d9521e41e94e359ba4d05bdad09ac0ff922fc5179a3215265e26c043d34df6964dabe53686d7e457f32838d7a1f2bbe4e4
6
+ metadata.gz: 1a271644761b887b3d61e427613a01a96bc53e8a454e25e8ae767639eb56e9b437211e202fae1994bf8540fa0979b606a0acec4e169b4efe3c1a28207a24ca77
7
+ data.tar.gz: 65169f13404161ae161d4c41f74fd409a2c2afebe6c7ff1375f87b570368f988aaf8706cf879a87ed83a8620ad86d9c269ff24f18b4721947d55a73b3a2cf058
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby-lambdas (0.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.11.3)
10
+ rake (10.5.0)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ bundler (~> 1.17)
17
+ minitest (~> 5.0)
18
+ rake (~> 10.0)
19
+ ruby-lambdas!
20
+
21
+ BUNDLED WITH
22
+ 1.17.2
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # RubyLambdas
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ruby/lambdas`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Expose Ruby object methods as lambdas (functions).
6
4
 
7
5
  ## Installation
8
6
 
@@ -109,20 +107,25 @@ Slugify = # Slugify =
109
107
  .>> Strings::Downcase # >> Strings::LowerCase \
110
108
  .>> Strings::GSub[' ', '-'] # >> Strings::ReplaceAll[' ', '-']
111
109
 
112
- # Reading the previous composition (Step by step)
113
- # 1. Convert a given object (first input) as a String
114
- # 2. Remove all whitespaces from both sides of a string.
115
- # 3. Convert a string to all lower case.
116
- # 4. Replace all occurrences of " " by "-".
117
-
118
- # Usage
110
+ # Reading the previous composition (Step by step):
111
+ # 1. Convert a given object (first input) as a String
112
+ # 2. Remove all whitespaces from both sides of a string.
113
+ # 3. Convert a string to all lower case.
114
+ # 4. Replace all occurrences of " " by "-".
119
115
 
116
+ #########
117
+ # Usage #
118
+ #########
120
119
  Slugify.(nil) # => ""
121
120
  Slugify.(1) # => "1"
122
121
  Slugify.(1.0) # => "1.0"
123
122
  Slugify.(' I WILL be a url slug ') # => "i-will-be-a-url-slug"
124
123
  ```
125
124
 
125
+ ### Do you like it?
126
+
127
+ So, look in [examples folder](https://github.com/serradura/ruby-lambdas/tree/master/examples) to see more ideas and benchmarks.
128
+
126
129
  ## Development
127
130
 
128
131
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/examples/01.rb ADDED
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ raise 'Wrong Ruby version!' unless RUBY_VERSION >= '2.6.0'
4
+
5
+ require 'bundler/inline'
6
+
7
+ gemfile do
8
+ source 'https://rubygems.org'
9
+
10
+ gem 'ruby-lambdas', require: 'ruby/lambdas'
11
+ gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
12
+ end
13
+
14
+ ############
15
+ # Examples #
16
+ ############
17
+
18
+ #
19
+ # Using common Method Chaining
20
+ #
21
+ def slugify2(value)
22
+ value.strip.downcase.gsub(' ', '-')
23
+ end
24
+
25
+ #
26
+ # Using Composable Lambdas
27
+ #
28
+ # -- Alternative syntax --
29
+ Slugify = # Slugify =
30
+ Strings::Strip # Strings::Trim \
31
+ .>> Strings::Downcase # >> Strings::LowerCase \
32
+ .>> Strings::GSub[' ', '-'] # >> Strings::ReplaceAll[' ', '-']
33
+
34
+ # -- Alternative syntax --
35
+ slug = Slugify.(' I WILL be a url slug ') # Slugify.call(' I WILL be a url slug ')
36
+ # Slugify[' I WILL be a url slug ']
37
+ p slug # => "i-will-be-a-url-slug"
38
+
39
+ #
40
+ # Using Data Pipeline with the `then` method & `ruby/lambdas`
41
+ #
42
+ def slugify(value)
43
+ value
44
+ .then(&Strings::Trim)
45
+ .then(&Strings::LowerCase)
46
+ .then(&Strings::ReplaceAll[' ', '-'])
47
+ end
48
+
49
+ p slugify(' I will be a url SLUG ') # => "i-will-be-a-url-slug"
50
+
51
+ ##############
52
+ # Benchmarks #
53
+ ##############
54
+
55
+ require 'benchmark/ips'
56
+
57
+ Benchmark.ips do |x|
58
+ x.report('method chaining') { slugify2(' I WILL be a url slug ') }
59
+
60
+ x.report('compose (.>>)') { Slugify.(' I WILL be a url slug ') }
61
+
62
+ x.report('pipeline (.then)') { slugify(' I WILL be a url slug ') }
63
+
64
+ x.compare!
65
+ end
66
+
67
+ # ruby -v examples/01.rb
68
+ # ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-darwin17]
69
+ # Warming up --------------------------------------
70
+ # method chaining 41.639k i/100ms
71
+ # compose (.>>) 41.931k i/100ms
72
+ # pipeline (.then) 32.379k i/100ms
73
+ # Calculating -------------------------------------
74
+ # method chaining 464.961k (± 1.9%) i/s - 2.332M in 5.016985s
75
+ # compose (.>>) 470.854k (± 1.6%) i/s - 2.390M in 5.077433s
76
+ # pipeline (.then) 351.887k (± 2.2%) i/s - 1.781M in 5.063616s
77
+
78
+ # Comparison:
79
+ # compose (.>>): 470853.9 i/s
80
+ # method chaining: 464960.6 i/s - same-ish: difference falls within error
81
+ # pipeline (.then): 351887.1 i/s - 1.34x slower
data/examples/02.rb ADDED
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ raise 'Wrong Ruby version!' unless RUBY_VERSION >= '2.6.0'
4
+
5
+ require 'bundler/inline'
6
+
7
+ gemfile do
8
+ source 'https://rubygems.org'
9
+
10
+ gem 'ruby-lambdas', require: 'ruby/lambdas'
11
+ gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
12
+ end
13
+
14
+ ############
15
+ # Examples #
16
+ ############
17
+
18
+ #
19
+ # Using Data Pipeline with the `then` method & `ruby/lambdas`
20
+ #
21
+ class Slugifier1
22
+ def initialize(sub, new_sub)
23
+ @sub = sub
24
+ @new_sub = new_sub
25
+ end
26
+
27
+ def call(value)
28
+ value
29
+ .then(&Strings::Strip)
30
+ .then(&Strings::Downcase)
31
+ .then(&Strings::GSub[@sub, @new_sub])
32
+ end
33
+ end
34
+
35
+ Slugify1 = Slugifier1.new(' ', '-')
36
+
37
+ # -- Alternative syntax --
38
+ p Slugify1.(' I will Be a urL slug ') # Slugify.call(' I will Be a urL slug ')
39
+
40
+ #
41
+ # Using Data Pipeline with the `then` method & `ruby/lambdas`
42
+ # & generates only once the replace function.
43
+ #
44
+ class Slugifier2
45
+ def initialize(sub, new_sub)
46
+ @replace = Strings::GSub[sub, new_sub]
47
+ end
48
+
49
+ def call(value)
50
+ value
51
+ .then(&Strings::Strip)
52
+ .then(&Strings::Downcase)
53
+ .then(&@replace)
54
+ end
55
+ end
56
+
57
+ Slugify2 = Slugifier2.new(' ', '-')
58
+
59
+ # -- Alternative syntax --
60
+ p Slugify2.(' I will Be a urL slug ') # Slugify.call(' I will Be a urL slug ')
61
+
62
+ #
63
+ # The code below is similar to the first implementation.
64
+ # It also uses the data pipeline with the `then` method.
65
+ # But instead of the `ruby/lambdas`, it defines instance private methods.
66
+ #
67
+ class Slugifier3
68
+ def initialize(sub, new_sub)
69
+ @sub = sub
70
+ @new_sub = new_sub
71
+ end
72
+
73
+ def call(value)
74
+ value
75
+ .then(&method(:trim))
76
+ .then(&method(:lower_case))
77
+ .then(&method(:replace))
78
+ end
79
+
80
+ private
81
+
82
+ def trim(str)
83
+ str.strip
84
+ end
85
+
86
+ def lower_case(str)
87
+ str.downcase
88
+ end
89
+
90
+ def replace(str)
91
+ str.gsub(@sub, @new_sub)
92
+ end
93
+ end
94
+
95
+ Slugify3 = Slugifier3.new(' ', '-')
96
+
97
+ p Slugify3.(' I will be a URL slug ')
98
+
99
+ #
100
+ # Use composition instead of pipeline.
101
+ #
102
+ class Slugifier4
103
+ def initialize(sub, new_sub)
104
+ @function =
105
+ Strings::Strip >> Strings::Downcase >> Strings::GSub[sub, new_sub]
106
+ end
107
+
108
+ def call(value)
109
+ @function.call(value)
110
+ end
111
+ end
112
+
113
+ Slugify4 = Slugifier4.new(' ', '-')
114
+
115
+ p Slugify4.(' I will be a URL slug ')
116
+
117
+ #
118
+ # Use only Lambdas instead of classes
119
+ #
120
+ Slugifier5 = -> (sub, new_sub) do
121
+ Strings::Strip >> Strings::Downcase >> Strings::GSub[sub, new_sub]
122
+ end
123
+
124
+ Slugify5 = Slugifier5.call(' ', '-')
125
+
126
+ p Slugify5.(' I will be a URL slug ')
127
+
128
+ #
129
+ # Using common Method Chaining
130
+ #
131
+ class Slugifier6
132
+ def initialize(sub, new_sub)
133
+ @sub = sub
134
+ @new_sub = new_sub
135
+ end
136
+
137
+ def call(value)
138
+ value.strip.downcase.gsub(@sub, @new_sub)
139
+ end
140
+ end
141
+
142
+ Slugify6 = Slugifier6.new(' ', '-')
143
+
144
+ p Slugify6.(' I will be a URL slug ')
145
+
146
+ ##############
147
+ # Benchmarks #
148
+ ##############
149
+
150
+ require 'benchmark/ips'
151
+
152
+ Benchmark.ips do |x|
153
+ x.report('Slugify1') { Slugify1.(' I WILL be a url slug ') }
154
+
155
+ x.report('Slugify2') { Slugify2.(' I WILL be a url slug ') }
156
+
157
+ x.report('Slugify3') { Slugify3.(' I WILL be a url slug ') }
158
+
159
+ x.report('Slugify4') { Slugify4.(' I WILL be a url slug ') }
160
+
161
+ x.report('Slugify5') { Slugify5.(' I WILL be a url slug ') }
162
+
163
+ x.report('Slugify6') { Slugify6.(' I WILL be a url slug ') }
164
+
165
+ x.compare!
166
+ end
167
+
168
+ # ruby -v examples/02.rb
169
+ # ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-darwin17]
170
+ # Warming up --------------------------------------
171
+ # Slugify1 32.149k i/100ms
172
+ # Slugify2 42.850k i/100ms
173
+ # Slugify3 18.885k i/100ms
174
+ # Slugify4 41.644k i/100ms
175
+ # Slugify5 42.273k i/100ms
176
+ # Slugify6 42.046k i/100ms
177
+ # Calculating -------------------------------------
178
+ # Slugify1 353.043k (± 1.1%) i/s - 1.768M in 5.009066s
179
+ # Slugify2 478.121k (± 1.2%) i/s - 2.400M in 5.019572s
180
+ # Slugify3 198.989k (± 1.7%) i/s - 1.001M in 5.031499s
181
+ # Slugify4 467.207k (± 1.4%) i/s - 2.374M in 5.081706s
182
+ # Slugify5 463.900k (± 5.0%) i/s - 2.325M in 5.026941s
183
+ # Slugify6 463.345k (± 1.5%) i/s - 2.355M in 5.082800s
184
+
185
+ # Comparison:
186
+ # Slugify2: 478121.3 i/s
187
+ # Slugify4: 467207.4 i/s - same-ish: difference falls within error
188
+ # Slugify5: 463900.4 i/s - same-ish: difference falls within error
189
+ # Slugify6: 463345.1 i/s - 1.03x slower
190
+ # Slugify1: 353043.2 i/s - 1.35x slower
191
+ # Slugify3: 198989.5 i/s - 2.40x slower
data/examples/03.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+
8
+ gem 'ruby-lambdas', require: 'ruby/lambdas'
9
+ end
10
+
11
+ ############
12
+ # Examples #
13
+ ############
14
+
15
+ p [2, 4, 8].map(&Numerics + 2) # => [4, 6, 10]
16
+ p [2, 4, 8].map(&Numerics - 2) # => [0, 2, 6]
17
+ p [2, 4, 8].map(&Numerics / 2) # => [1, 2, 4]
18
+ p [2, 4, 8].map(&Numerics * 2) # => [4, 8, 16]
19
+
20
+ # ---
21
+
22
+ p [2, 4, 8].select(&Numerics > 2) # => [4, 8]
23
+ p [2, 4, 8].select(&Numerics >= 2) # => [2, 4, 8]
24
+ p [2, 4, 8].select(&Numerics < 2) # => []
25
+ p [2, 4, 8].select(&Numerics <= 2) # => [2]
data/examples/04.rb ADDED
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ raise 'Wrong Ruby version!' unless RUBY_VERSION >= '2.6.0'
4
+
5
+ require 'bundler/inline'
6
+
7
+ gemfile do
8
+ source 'https://rubygems.org'
9
+
10
+ gem 'ruby-lambdas', require: 'ruby/lambdas'
11
+ gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
12
+ end
13
+
14
+ ############
15
+ # Examples #
16
+ ############
17
+
18
+ Student = Struct.new(:name, :grade, keyword_init: true)
19
+
20
+ STUDENTS = [
21
+ { name: 'Rodrigo', grade: 6 },
22
+ { name: 'Talita' , grade: 9 },
23
+ { name: 'Bella' , grade: 10 },
24
+ { name: 'Lara' , grade: 10 }
25
+ ].map &Student.method(:new)
26
+
27
+ ByName = -> student { student.name }
28
+ FetchGrade = -> student { student.grade }
29
+ IsApproved = FetchGrade >> (Numerics >= 9)
30
+
31
+ #
32
+ # Declarative approach (using functions instead of blocks)
33
+ #
34
+ p STUDENTS.select(&IsApproved).map(&ByName)
35
+
36
+ #
37
+ # An Imperative version from the previous example
38
+ #
39
+ p STUDENTS.select{ |student| student.grade >= 9 }
40
+ .map{ |student| student.name }
41
+
42
+ ##############
43
+ # Benchmarks #
44
+ ##############
45
+
46
+ require 'benchmark/ips'
47
+
48
+ IsApproved2 = -> student { student.grade >= 9 }
49
+
50
+ Benchmark.ips do |x|
51
+ x.report('Imperative') do
52
+ STUDENTS.select { |student| student.grade >= 9 }
53
+ end
54
+
55
+ x.report('Declarative (with composition)') do
56
+ STUDENTS.select(&IsApproved)
57
+ end
58
+
59
+ x.report('Declarative (without composition)') do
60
+ STUDENTS.select(&IsApproved2)
61
+ end
62
+
63
+ x.compare!
64
+ end
65
+
66
+ # ruby -v examples/02.rb
67
+ # ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-darwin17]
68
+ # Warming up --------------------------------------
69
+ # Imperative 155.896k i/100ms
70
+ # Declarative (with composition)
71
+ # 58.468k i/100ms
72
+ # Declarative (without composition)
73
+ # 153.103k i/100ms
74
+ # Calculating -------------------------------------
75
+ # Imperative 2.542M (± 1.3%) i/s - 12.783M in 5.029394s
76
+ # Declarative (with composition)
77
+ # 690.140k (± 1.6%) i/s - 3.508M in 5.084486s
78
+ # Declarative (without composition)
79
+ # 2.408M (± 1.5%) i/s - 12.095M in 5.024628s
80
+
81
+ # Comparison:
82
+ # Imperative: 2542164.1 i/s
83
+ # Declarative (without composition): 2407753.3 i/s - 1.06x slower
84
+ # Declarative (with composition): 690140.5 i/s - 3.68x slower
@@ -0,0 +1,34 @@
1
+ module RubyLambdas
2
+ module Numerics
3
+ module ToExport
4
+ #
5
+ # Operators
6
+ #
7
+ Add = -> (a, b) { a + b }
8
+
9
+ Divide = -> (a, b) { a / b }
10
+
11
+ Subtract = -> (a, b) { a - b }
12
+
13
+ Multiply = -> (a, b) { a * b }
14
+
15
+ #
16
+ # Comparables
17
+ #
18
+ GreaterThan = -> (a, b) { a > b }
19
+
20
+ GreaterThanOrEqual = -> (a, b) { a >= b }
21
+
22
+ LessThan = -> (a, b) { a < b }
23
+
24
+ LessThanOrEqual = -> (a, b) { a <= b }
25
+ end
26
+
27
+ ALIASES = {
28
+ GreaterThan: :Gt,
29
+ GreaterThanOrEqual: :Gte,
30
+ LessThan: :Lt,
31
+ LessThanOrEqual: :Lte,
32
+ }.freeze
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module Numerics
2
+ require_relative "import"
3
+ require_relative "numerics/to_export"
4
+
5
+ RubyLambdas::Import.(from: RubyLambdas::Numerics, to: self)
6
+
7
+ #
8
+ # Operators
9
+ #
10
+ def self.+(a)
11
+ Add[a]
12
+ end
13
+
14
+ def self./(b)
15
+ -> a { Divide[a, b] }
16
+ end
17
+
18
+ def self.-(b)
19
+ -> a { Subtract[a, b] }
20
+ end
21
+
22
+ def self.*(a)
23
+ Multiply[a]
24
+ end
25
+
26
+ #
27
+ # Comparables
28
+ #
29
+ def self.>(b)
30
+ -> a { GreaterThan[a, b] }
31
+ end
32
+
33
+ def self.>=(b)
34
+ -> a { GreaterThanOrEqual[a, b] }
35
+ end
36
+
37
+ def self.<(b)
38
+ -> a { LessThan[a, b] }
39
+ end
40
+
41
+ def self.<=(b)
42
+ -> a { LessThanOrEqual[a, b] }
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module RubyLambdas
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/ruby/lambdas.rb CHANGED
@@ -2,5 +2,6 @@ require "ruby/lambdas/version"
2
2
 
3
3
  module RubyLambdas
4
4
  require_relative "lambdas/strings"
5
+ require_relative "lambdas/numerics"
5
6
  require_relative "lambdas/objects"
6
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lambdas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-29 00:00:00.000000000 Z
11
+ date: 2019-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -63,13 +63,20 @@ files:
63
63
  - ".travis.yml"
64
64
  - CODE_OF_CONDUCT.md
65
65
  - Gemfile
66
+ - Gemfile.lock
66
67
  - LICENSE.txt
67
68
  - README.md
68
69
  - Rakefile
69
70
  - bin/console
70
71
  - bin/setup
72
+ - examples/01.rb
73
+ - examples/02.rb
74
+ - examples/03.rb
75
+ - examples/04.rb
71
76
  - lib/ruby/lambdas.rb
72
77
  - lib/ruby/lambdas/import.rb
78
+ - lib/ruby/lambdas/numerics.rb
79
+ - lib/ruby/lambdas/numerics/to_export.rb
73
80
  - lib/ruby/lambdas/objects.rb
74
81
  - lib/ruby/lambdas/objects/to_export.rb
75
82
  - lib/ruby/lambdas/strings.rb