lab42_streams 0.2.0 → 0.3.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
- SHA1:
3
- metadata.gz: d8d00b456b8ce625579e3dc38bf492d5f10f33c8
4
- data.tar.gz: a454254eb45b9315675e2d64379186c9b3e7b71b
2
+ SHA256:
3
+ metadata.gz: e8f831b639a52dd52db85790b4fa4f7a558d4141b8deaf0ba7cd406f59970578
4
+ data.tar.gz: 58bfe3bfe2d31b694061a704ec6fbb30bbf901fe0e4134f91026edaceac22913
5
5
  SHA512:
6
- metadata.gz: a9da27d1e87aae306204fe530f480aef2196de0c33aa18b0f3967a51230a838dc741c78861d7d4cd25da32edc0d134a894bc38672c40c5833209c4fff81ce4c7
7
- data.tar.gz: 89ae1665b491b160b0c58338b3f4c1bc9eeae3cf0d9545456d6f2ef05670b14dd1ce9d47bd460a5493eeb3bedb0559d87b6eee8b2b2324d68078bdb5db6e5cc6
6
+ metadata.gz: 17bb41d95481d19badab24f90ec1935f4450c19b65435000ba93721b602934506c665a239f524241ab4cff7ef127a84b7cdf4312cba74bb7b4b0eab2ac4c3ba2
7
+ data.tar.gz: 726f43fcf1c28fc99de3b1792fda975bdb4b9d7ed349aa380b95192af53b048def7717193065d6917a7e235cbddf36eb4ad63e2aa617eceeaa74bb15bd873f00
data/README.md CHANGED
@@ -1,14 +1,136 @@
1
+ [![Build Status](https://travis-ci.org/RobertDober/lab42_streams.svg?branch=master)](https://travis-ci.org/RobertDober/lab42_streams)
2
+ [![Code Climate](https://codeclimate.com/github/RobertDober/lab42_streams/badges/gpa.svg)](https://codeclimate.com/github/RobertDober/lab42_streams)
3
+ [![Issue Count](https://codeclimate.com/github/RobertDober/lab42_streams/badges/issue_count.svg)](https://codeclimate.com/github/RobertDober/lab42_streams)
4
+ [![Test Coverage](https://codeclimate.com/github/RobertDober/lab42_streams/badges/coverage.svg)](https://codeclimate.com/github/RobertDober/lab42_streams)
5
+ [![Gem Version](https://badge.fury.io/rb/lab42_streams.svg)](http://badge.fury.io/rb/lab42_streams)
6
+
1
7
  # lab42\_streams
2
8
 
3
- Bringing Streams to Ruby
9
+ ## Bringing Streams to Ruby
4
10
 
5
11
  An excellent introduction into `Streams` can be found [here](http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/6a-streams-part-1/)
6
12
 
7
- [![Build Status](https://travis-ci.org/RobertDober/lab42_streams.svg?branch=master)](https://travis-ci.org/RobertDober/lab42_streams)
8
- [![Code Climate](https://codeclimate.com/github/RobertDober/lab42_streams/badges/gpa.svg)](https://codeclimate.com/github/RobertDober/lab42_streams)
9
- [![Test Coverage](https://codeclimate.com/github/RobertDober/lab42_streams/badges/coverage.svg)](https://codeclimate.com/github/RobertDober/lab42_streams)
10
- [![Gem Version](https://badge.fury.io/rb/lab42_streams.svg)](http://badge.fury.io/rb/lab42_streams)
13
+ ## Basic Stream Tutorial
14
+
15
+ Streams are lazy, immutable lists, or for the purists, lazy cons cells (well the tail/cdr is lazy, the head/car is not).
16
+
17
+ A first example
18
+
19
+ ### Infinite Streams
20
+
21
+ Given the following definition
22
+
23
+ ```ruby :include
24
+ def fibs a=0, b=1
25
+ cons_stream a do
26
+ fibs b, a+b
27
+ end
28
+ end
29
+ ```
30
+
31
+ The following spec will be satisfied
32
+
33
+ ```ruby :example
34
+ expect(fibs.drop(1000).head).
35
+ to eq(43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875)
36
+ ```
37
+
38
+ There are several things to remember here:
39
+
40
+ * The tail of a stream is *always* provided as block or lambda, the only way in ruby to
41
+ implement a normal order parameter.
42
+
43
+ * The result of the tail (that is when the delay or promise the tail defines is forced or realised)
44
+ must be a `Stream`. This has to be automated into your reasoning about `Streams` lest you will
45
+ have difficulties to come up with stream based solutions.
46
+
47
+ * When the promise of the tail is forced the stack frame of the `cons_stream` call is not active
48
+ any more, there will be no stack overflow.
49
+
50
+
51
+ ### Transformation Chain
52
+
53
+ One major advantage of streams (and lazy evaluation in general) is that transformations can be composed without any performance penality.
54
+
55
+ While for example the following code would be terribly inefficent
56
+
57
+ ```ruby
58
+ elements = { 2 => "two", 4 => "four" }
59
+ list = 1..2 # but imagine a very large value of 2
60
+ list.map{ |x| x * 2 }.map{ |x| elements[x] }.map(&:reverse)
61
+ ```
62
+
63
+ the following stream based code is not.
64
+
65
+ ```ruby
66
+
67
+ translation = { [true,true] => "fizzbuzz", [true, false] => "fizz", [false, true] => "buzz" }
68
+ integers = Stream.iterate 0, :succ
69
+ fizzbuzz = integers
70
+ .reject{ |x| (x%100).zero? }
71
+ .map{ |i| [(i%3).zero?,(i%5).zero?,i] }
72
+ .map{ |f,b,i| translation.fetch([f,b],i) }
73
+ ```
74
+
75
+ The reason for this is that, up to now, no single computation has been done, but _promises_ for doing so
76
+ have been registered. Only when we eventually force values these computations will be executed and then
77
+ it will make little difference if we execute one complex computation or five simple ones.
78
+
79
+ And as we operate on **infinite** streams it becomes obvious that the implementation must delay up to the end.
80
+
81
+ ### Memoization
82
+
83
+ The fourth point to know about `Streams` is that:
84
+
85
+ * All promises are **memoized**.
86
+
87
+
88
+
89
+ Only for that reason the following naïve, but elegant implementation of the fibonacci sequence has O(N) runtime
90
+ characteristics, and the result can be computed:
91
+
92
+ ```ruby :include
93
+
94
+ let(:fibs1) do
95
+ cons_stream(0){
96
+ cons_stream(1){
97
+ combine_streams fibs1, fibs1.tail, :+
98
+ }
99
+ }
100
+ end
101
+ ```
102
+
103
+ ```ruby :example
104
+ expect(fibs1.drop(1000).head)
105
+ .to eq(43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875)
106
+
107
+ ```
108
+
109
+
110
+ ## Finite Streams
111
+
112
+ Finite Streams are implemented the same way LISP imlements lists, by providing an _End_Marker_. What is `nil` in LISP
113
+ is `empty_stream` in Ruby. As a matter of fact the `empty_stream` method returns a singleton called `Lab42::Stream::Empty` which
114
+ is also accessible via `EmptyStream` if you required the lib with `require 'lab42/stream/auto_import'` which is true for the demos.
115
+
116
+ Here is an example of a finite stream
117
+
118
+ ```ruby :include
119
+ let(:digits){ finite_stream( 0..9 ) }
120
+ ```
121
+
122
+ Now the following all hold
123
+
124
+ ```ruby :example
125
+ expect(digits.drop(9).head).to eq(9)
126
+ ```
11
127
 
128
+ ```ruby :example
129
+ expect(digits.drop(10)).to be_empty
130
+ ```
12
131
 
132
+ or alternatively
13
133
 
14
- Please see the [QED](http://rubyworks.github.io/qed/) demos [here](https://github.com/RobertDober/lab42_streams/blob/master/demo) for details.
134
+ ```ruby :example
135
+ expect(digits.drop(10)).to eq(EmptyStream)
136
+ ```
@@ -4,8 +4,5 @@ Stream = Lab42::Stream
4
4
  EmptyStream = Lab42::Stream::EmptyStream
5
5
 
6
6
  module Kernel
7
- def iterate *args, &blk
8
- Stream.iterate( *args, &blk )
9
- end
10
7
  alias_method :stream_by, :iterate
11
8
  end # module Kernel
@@ -2,7 +2,7 @@ module Lab42
2
2
  class Stream
3
3
  module ClassMethods
4
4
  def iterate arg, beh=nil, &blk
5
- beh = Behavior.make( beh, &blk)
5
+ beh = Behavior.make(beh, &blk)
6
6
  __iterate__ arg, beh
7
7
  end
8
8
 
@@ -39,11 +39,9 @@ module Kernel
39
39
  when Range
40
40
  _finite_stream_from_range enum
41
41
  when Array
42
- return empty_stream if enum.empty?
43
- cons_stream(enum.first){ finite_stream(enum.drop(1)) }
42
+ _finite_stream_from_ary enum
44
43
  when Hash
45
- return empty_stream if enum.empty?
46
- cons_stream(enum.first){ finite_stream(enum.without(enum.first.first)) }
44
+ _finite_stream_from_hash enum
47
45
  when Enumerator
48
46
  _finite_stream_from_enumerator! enum.to_enum
49
47
  else
@@ -51,7 +49,6 @@ module Kernel
51
49
  end
52
50
  end
53
51
 
54
-
55
52
  def flatmap stream, *args, &blk
56
53
  stream.flatmap( *args, &blk )
57
54
  end
@@ -89,10 +86,20 @@ module Kernel
89
86
 
90
87
  private
91
88
 
89
+ def _finite_stream_from_ary ary
90
+ return empty_stream if ary.empty?
91
+ cons_stream(ary.first){ finite_stream(ary.drop(1)) }
92
+ end
93
+
92
94
  def _finite_stream_from_boundaies fst, lst
93
95
  return empty_stream if fst > lst
94
96
  cons_stream(fst){ _finite_stream_from_boundaies fst.succ, lst }
95
97
  end
98
+
99
+ def _finite_stream_from_hash hsh
100
+ return empty_stream if hsh.empty?
101
+ cons_stream(hsh.first){ finite_stream(hsh.without(hsh.first.first)) }
102
+ end
96
103
 
97
104
  def _finite_stream_from_enumerator! enum
98
105
  cons_stream( enum.next ){ _finite_stream_from_enumerator! enum }
@@ -1,5 +1,5 @@
1
1
  module Lab42
2
2
  class Stream
3
- Version = "0.2.0"
3
+ Version = "0.3.0"
4
4
  end # class Stream
5
5
  end # module Lab42
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lab42_streams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Dober
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-24 00:00:00.000000000 Z
11
+ date: 2024-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: forwarder2
@@ -38,76 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.4'
41
- - !ruby/object:Gem::Dependency
42
- name: pry-byebug
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 3.4.2
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 3.4.2
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.5'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.5'
69
- - !ruby/object:Gem::Dependency
70
- name: qed
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.9'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '2.9'
83
- - !ruby/object:Gem::Dependency
84
- name: ae
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '1.8'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '1.8'
97
- - !ruby/object:Gem::Dependency
98
- name: simplecov
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '0.13'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '0.13'
111
41
  description: Lazy Evaluation, Streams, Enumerator#Lazy
112
42
  email: robert.dober@gmail.com
113
43
  executables: []
@@ -135,7 +65,7 @@ homepage: https://github.com/RobertDober/lab42_streams
135
65
  licenses:
136
66
  - MIT
137
67
  metadata: {}
138
- post_install_message:
68
+ post_install_message:
139
69
  rdoc_options: []
140
70
  require_paths:
141
71
  - lib
@@ -143,16 +73,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
73
  requirements:
144
74
  - - ">="
145
75
  - !ruby/object:Gem::Version
146
- version: 2.4.0
76
+ version: 3.3.5
147
77
  required_rubygems_version: !ruby/object:Gem::Requirement
148
78
  requirements:
149
79
  - - ">="
150
80
  - !ruby/object:Gem::Version
151
81
  version: '0'
152
82
  requirements: []
153
- rubyforge_project:
154
- rubygems_version: 2.6.8
155
- signing_key:
83
+ rubygems_version: 3.5.16
84
+ signing_key:
156
85
  specification_version: 4
157
- summary: Streams for Ruby 2.0
86
+ summary: Streams for Ruby 3.3.5
158
87
  test_files: []