ronad 0.9.0 → 0.10.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: 92c3fe5954c20636ef0adfda0823d73b1c3c91a9778bc6698d9be5538c22d402
4
- data.tar.gz: de98fafde865cb62229efb3163c708349f15d2922e6cb860c75c6f69a005b9cd
3
+ metadata.gz: aae96a5293971c4033fb68485338315e17f1f0c307e11f50c57f2e2583e81067
4
+ data.tar.gz: 3eecd824510dc9fa3ee01742797bac4c7a0ab7ffe949498a4c1d2074d320793f
5
5
  SHA512:
6
- metadata.gz: d7da852fd7409736474db7734b38fb2ea2caa558830a26c12499bc6ede51bb8c59c24c896f344c24c3070dc3483015cdce40789eb6b14ea655a89028479b395b
7
- data.tar.gz: 99b5d6de76fb2f78e204284170e71eccf792a6108421cc3cccc705eb4d31f685e284d003f90d6c7cd12a6f8b322d175acd7c344321dd2e6ff372cd67cb235f36
6
+ metadata.gz: 5264e71387940e8728026b6fd524f0e237b81200c05e2abe4840d96a3ee7aa8e2d2e453af5e70dc117d2e9f4db0ed86c8052ee36bc49d632a670d17ffcd40927
7
+ data.tar.gz: 92b79c02a184d29a6a86ce2c01fdbc6efc201105d49debfcbd12bb68236ada59ac9f97683930ed8d7521bd1667e716e8fe502206b17a7dc6854883f2bfbaaaa3
@@ -0,0 +1,89 @@
1
+ module Ronad
2
+ # Chain operations on lists that can possibly return other lists.
3
+ #
4
+ # sentence = 'hello-there my-friend@good-bye my-pal'
5
+ #
6
+ # words = sentence.split('@').flat_map do |partials|
7
+ # partials.split('-').map do |word|
8
+ # word + '!'
9
+ # end
10
+ # end
11
+ #
12
+ # Or using Many:
13
+ #
14
+ # word = Many(sentence).split('@').split('-') + '!'
15
+ # words = word.value
16
+ #
17
+ # A Many can be useful for tranversing 'has many' relationships in a
18
+ # database. For example given the following relations with each relationship
19
+ # having 0 or more:
20
+ #
21
+ # - store has many products
22
+ # - product has many variants
23
+ # - variant has many inventory_units
24
+ #
25
+ # To obtain all the inventory_units of a store:
26
+ #
27
+ # store.products.flat_map(&:variants).flat_map(&:inventory_units)
28
+ #
29
+ # Or if a certain parameterized scope had to be used:
30
+ #
31
+ # store.products.flat_map do |product|
32
+ # prodcut.variants.where(some_state: true).flat_map do |variant|
33
+ # variant.inventory_units.where(physical: true)
34
+ # end
35
+ # end
36
+ #
37
+ # With Many:
38
+ #
39
+ # Many(store).products.variants.where(some_state: true).inventory_units.where(physical: true)
40
+ # .value
41
+ #
42
+ # A Many will also remove nil values:
43
+ #
44
+ # Many([1,2,nil,4,nil]).value #=> [1,2,4]
45
+ class Many < Monad
46
+ # Wraps a value in the Many monad.
47
+ #
48
+ # @param value - Does not need to be an enumerable as
49
+ # it will be wrapped in an Array.
50
+ # @param return_lazy - specifies if #monad_value should return a lazy
51
+ # enumerator. If left as nil, then #monad_value will return a lazy
52
+ # enumerator if one was initially provided to the constructor.
53
+ def initialize(value, return_lazy: nil)
54
+ @return_lazy = if return_lazy.nil?
55
+ value.is_a? Enumerator::Lazy
56
+ else
57
+ return_lazy
58
+ end
59
+
60
+ if value.is_a? Enumerable
61
+ @value = value.lazy
62
+ else
63
+ @value = Array(value).lazy
64
+ end
65
+ end
66
+
67
+
68
+ def and_then &b
69
+ from_value @value.reject(&:nil?).flat_map(&b)
70
+ end
71
+
72
+ # Returns the underlying value of the many. Always an Enumerator, sometimes
73
+ # lazy.
74
+ # @see #initialize
75
+ def monad_value
76
+ if @return_lazy
77
+ super
78
+ else
79
+ super.to_a
80
+ end
81
+ end
82
+
83
+ protected
84
+
85
+ def from_value(value)
86
+ self.class.new(value, return_lazy: @return_lazy)
87
+ end
88
+ end
89
+ end
@@ -37,28 +37,6 @@ module Ronad
37
37
  end
38
38
  end
39
39
 
40
- # "Fails" a maybe given a certain condition. If the condition is `false`
41
- # then Maybe(nil) will be returned. Useful for performing side-effects
42
- # given a certain condition
43
- #
44
- # Maybe([]).and_then do |value|
45
- # value.each(&:some_operation)
46
- # OtherModule.finalize! # Side Effect should only happen if there
47
- # end # are any values
48
- #
49
- # The following `and_then` only executes if `value` responds truthy to any?
50
- #
51
- # Maybe([]).continue(&:any?).and_then do |value|
52
- # value.each(&:some_operation)
53
- # OtherModule.finalize!
54
- # end
55
- # @return [Monad]
56
- def continue
57
- and_then do |value|
58
- value if yield value
59
- end
60
- end
61
-
62
40
  # "Fails" a maybe given a certain condition. If the condition is `true`
63
41
  # then Maybe(nil) will be returned.
64
42
  #
@@ -60,6 +60,29 @@ module Ronad
60
60
  end
61
61
 
62
62
 
63
+ # "Fails" a maybe given a certain condition. If the condition is `false`
64
+ # then Maybe(nil) will be returned. Useful for performing side-effects
65
+ # given a certain condition
66
+ #
67
+ # Maybe([]).and_then do |value|
68
+ # value.each(&:some_operation)
69
+ # OtherModule.finalize! # Side Effect should only happen if there
70
+ # end # are any values
71
+ #
72
+ # The following `and_then` only executes if `value` responds truthy to any?
73
+ #
74
+ # Maybe([]).continue(&:any?).and_then do |value|
75
+ # value.each(&:some_operation)
76
+ # OtherModule.finalize!
77
+ # end
78
+ # @return [Monad]
79
+ def continue
80
+ and_then do |value|
81
+ value if yield value
82
+ end
83
+ end
84
+
85
+
63
86
  private
64
87
 
65
88
  # Provides convinience for chaining methods together while maintaining a
@@ -0,0 +1,26 @@
1
+ module Ronad
2
+ # A One is similar to a Many but does not flatten the results if #and_then
3
+ # produces another list.
4
+ #
5
+ # urls = %w[
6
+ # example.com?p1=a&p2=b
7
+ # example.com?z1=5&y1=9
8
+ # ]
9
+ #
10
+ # one(urls)
11
+ # .split('?')
12
+ # .last # a Many would have flatten the #split and #last would be called on a String
13
+ # .split('&')
14
+ # .last
15
+ # .split('=')
16
+ # .first
17
+ # .value #=> ['p2', 'y1']
18
+ #
19
+ # A One can be used for providing a familiar interface to a function that
20
+ # does not expect the flattening behavior of Many.
21
+ class One < Many
22
+ def and_then &b
23
+ from_value @value.reject(&:nil?).map(&b)
24
+ end
25
+ end
26
+ end
@@ -1,10 +1,14 @@
1
1
  require 'ronad/maybe'
2
+ require 'ronad/many'
3
+ require 'ronad/one'
2
4
  require 'ronad/just'
3
5
  require 'ronad/just_one'
4
6
  require 'ronad/default'
5
7
  require 'ronad/eventually'
6
8
 
7
9
  def Maybe(*values) ; Ronad::Maybe.from_multiple_values(*values) end
10
+ def Many(value, **kargs) ; Ronad::Many.new(value, **kargs) end
11
+ def One(value, **kargs) ; Ronad::One.new(value, **kargs) end
8
12
  def Just(value); Ronad::Just.new(value) end
9
13
  def JustOne(*values); Ronad::JustOne.new(*values) end
10
14
  def Default(fallback, value) ; Ronad::Default.new(fallback, value) end
@@ -1,3 +1,3 @@
1
1
  module Ronad
2
- VERSION = '0.9.0'
2
+ VERSION = '0.10.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ronad
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uri Gorelik
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-10 00:00:00.000000000 Z
11
+ date: 2018-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -101,8 +101,10 @@ files:
101
101
  - lib/ronad/eventually.rb
102
102
  - lib/ronad/just.rb
103
103
  - lib/ronad/just_one.rb
104
+ - lib/ronad/many.rb
104
105
  - lib/ronad/maybe.rb
105
106
  - lib/ronad/monad.rb
107
+ - lib/ronad/one.rb
106
108
  - lib/ronad/sugar.rb
107
109
  - lib/ronad/version.rb
108
110
  - lib/sugar.rb