ruby-lambdas 0.3.0 → 0.4.0

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