ronad 0.9.0 → 0.10.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: 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