lazy_string 0.4.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt CHANGED
@@ -1,20 +1,19 @@
1
- Copyright (c) 2022 Aaron Beckerman
1
+ Copyright (c) 2024 Aaron Beckerman
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
10
9
 
11
- The above copyright notice and this permission notice shall be included
12
- in all copies or substantial portions of the Software.
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
13
12
 
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.txt CHANGED
@@ -1,43 +1,28 @@
1
1
  LazyString
2
2
 
3
3
  LazyString is a Ruby class for computing strings only when necessary. This is
4
- useful when computing the string is expensive but the string is unlikely to be
5
- used: an error message passed as an argument, for example.
4
+ useful when computing the string is expensive but the string might never be
5
+ used.
6
6
 
7
- Thanks to duck typing and Ruby's standard conversion protocols, you can pass
8
- an instance of LazyString to many methods that ask for a string.
7
+ Thanks to Ruby's duck typing and conversion protocols, you can often use an
8
+ instance of LazyString where you previously used an instance of String.
9
9
 
10
10
 
11
11
  Usage
12
12
 
13
- LazyString is packaged as a RubyGem. Once you've installed it and required the
14
- file, you can create a lazy string by passing a block to LazyString.new:
13
+ LazyString is packaged as a gem. Once you've installed it and loaded the file,
14
+ you can create a lazy string by sending new to LazyString with a block. The
15
+ block should return an object that converts to a string:
15
16
 
16
17
  ls = LazyString.new { "answer = #{expensive_computation}" }
17
18
 
18
- The block (and therefore expensive_computation) will not be called immediately.
19
- But later, if #to_str or #to_s is sent to the lazy string, the block will be
20
- called with no arguments in order to create the real string.
19
+ The block (and therefore expensive_computation) will not be run immediately.
20
+ But later, if to_str or to_s is sent to the lazy string, the saved proc
21
+ representing your block will be called with no arguments and the returned
22
+ object converted to create the real string.
21
23
 
22
- # String interpolation calls #to_s automatically.
24
+ # String interpolation sends to_s.
23
25
  s = "Lazy string computes this: #{ls}"
24
26
 
25
- Once the string is computed, it will be saved, so any future invocations of
26
- #to_str or #to_s will not perform the computation again.
27
-
28
-
29
- Compatibility
30
-
31
- This works on version 1.8.7 and later of Matz's Ruby Interpreter. (At the time
32
- of this writing, 2.2.3 is the current version.)
33
-
34
-
35
- Author
36
-
37
- This software was written by Aaron Beckerman.
38
-
39
-
40
- License
41
-
42
- This software is distributed under the MIT License (also known as the Expat
43
- License). See the LICENSE.txt file for details.
27
+ Once the string is computed, it will be saved, so sending to_str or to_s again
28
+ will not cause the computation to be performed again.
data/lazy_string.gemspec CHANGED
@@ -1,19 +1,14 @@
1
- # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "lazy_string"
5
-
6
- Gem::Specification.new do |gem|
7
- gem.name = 'lazy_string'
8
- gem.version = LazyString::VERSION
9
- gem.authors = ['Aaron Beckerman']
10
- gem.description = %q{This library provides LazyString, a class for computing strings only when necessary. This is useful when computing the string is expensive but the string is unlikely to be used: an error message passed as an argument, for example.}
11
- gem.summary = %q{A Ruby library for lazily computing strings.}
12
- gem.license = 'MIT'
13
- gem.required_ruby_version = '>= 1.8.7'
14
-
15
- gem.files = %w{LICENSE.txt README.txt lazy_string.gemspec lib/lazy_string.rb test/lazy_string_test.rb}
16
- gem.executables = %w{}
17
- gem.test_files = %w{test/lazy_string_test.rb}
18
- gem.require_paths = %w{lib}
1
+ Gem::Specification.new do |s|
2
+ s.name = "lazy_string"
3
+ s.version = "0.7.0"
4
+ s.authors = ["Aaron Beckerman"]
5
+ s.summary = "A class for computing strings only when necessary."
6
+ s.description = "This library provides LazyString, a class for computing" \
7
+ " strings only when necessary. This is useful when computing the string" \
8
+ " is expensive but the string might never be used."
9
+ s.licenses = ["MIT"]
10
+ s.files = ["LICENSE.txt", "README.txt", "lazy_string.gemspec",
11
+ "lib/lazy_string.rb", "test/lazy_string_test.rb"]
12
+ s.test_files = ["test/lazy_string_test.rb"]
13
+ s.required_ruby_version = ">= 1.8.7"
19
14
  end
data/lib/lazy_string.rb CHANGED
@@ -1,46 +1,46 @@
1
1
  ##
2
- # LazyString is a class for computing strings only when necessary. This is
3
- # useful when computing the string is expensive but the string is unlikely to
4
- # be used: an error message passed as an argument, for example.
5
- #
2
+ # A class for computing strings only when necessary.
3
+
6
4
  class LazyString
7
- ##
8
- # The version string.
9
- #
10
- VERSION = '0.4.0'
11
5
 
12
6
  ##
13
- # Creates a new lazy string. The block argument will be saved for later use
14
- # by #to_str. If no block argument is given, it will default to a block that
15
- # returns an empty string.
16
- #
17
- def initialize(&block)
18
- @block = block || lambda { '' }
7
+ # Creates a new lazy string. It saves the block as a proc for later use by
8
+ # #to_str. If no block is given, it saves a proc that returns an empty
9
+ # string.
10
+
11
+ def initialize &prc
12
+ @prc = prc || ::Proc.new { "" }
13
+ nil
19
14
  end
20
15
 
21
16
  ##
22
- # A synonym for #to_str.
23
- #
17
+ # Computes the string if necessary and returns it. It delegates to #to_str.
18
+
24
19
  def to_s
25
20
  to_str
26
21
  end
27
22
 
28
23
  ##
29
- # Returns the computed string. It will compute the string by calling (with no
30
- # arguments) the block passed to ::new. If the block's return value responds
31
- # to the \to_str message, \to_str will be sent to it to create the string.
32
- # Otherwise, \to_s will be sent to it. The computed string will be saved,
33
- # so subsequent invocations of this method will not cause the block to be
34
- # called again.
35
- #
24
+ # Computes the string if necessary and returns it. It computes the string by
25
+ # calling, with no arguments, the saved proc representing the block passed to
26
+ # ::new. If an object is returned, this method converts it to a string and
27
+ # returns the result. It converts the object to a string by sending \to_str
28
+ # to the object if it responds to that message and \to_s otherwise. It saves
29
+ # the computed string, so subsequent invocations of this method will not
30
+ # recompute the string. If an exception is raised, this method immediately
31
+ # raises that exception and does not save any result.
32
+
36
33
  def to_str
37
- @str ||= begin
38
- result = @block.call
39
- if result.respond_to?(:to_str)
34
+ if defined? @str
35
+ @str
36
+ else
37
+ result = @prc.call
38
+ @str = if result.respond_to? :to_str
40
39
  result.to_str
41
40
  else
42
41
  result.to_s
43
42
  end
44
43
  end
45
44
  end
45
+
46
46
  end
@@ -1,55 +1,162 @@
1
- require 'lazy_string'
1
+ # Sections that create local variables are in class definitions so that later
2
+ # sections cannot accidentally reference those local variables.
2
3
 
3
- Class == LazyString.class or fail
4
+ require "lazy_string"
4
5
 
5
- String == LazyString::VERSION.class or fail
6
+ # LazyString should be a class.
7
+ fail "" unless Class.equal? LazyString.class
6
8
 
7
- lambda do
8
- obj = Object.new
9
- LazyString.new { obj.freeze }
10
- !obj.frozen? or fail
11
- end.call
9
+ # LazyString.new should return an instance of LazyString.
10
+ fail "" unless LazyString.equal? LazyString.new.class
12
11
 
13
- LazyString.new.respond_to?(:to_str) or fail
12
+ # LazyString.new should raise an exception if any non-block arguments are sent.
13
+ begin
14
+ LazyString.new nil
15
+ rescue ArgumentError
16
+ else
17
+ fail ""
18
+ end
19
+ begin
20
+ LazyString.new(nil) {}
21
+ rescue ArgumentError
22
+ else
23
+ fail ""
24
+ end
14
25
 
15
- LazyString.new.respond_to?(:to_s) or fail
26
+ # The block should not be called when creating a lazy string.
27
+ class ::Object
28
+ calls = 0
29
+ LazyString.new { calls += 1 }
30
+ fail "" unless 0 == calls
31
+ end
16
32
 
17
- '' == LazyString.new.to_str or fail
33
+ # An instance of LazyString should say it responds to to_str and to_s.
34
+ fail "" unless LazyString.new.respond_to? :to_str
35
+ fail "" unless LazyString.new.respond_to? :to_s
18
36
 
19
- lambda do
20
- obj = Object.new
21
- def obj.to_str; 'to_str' end
22
- def obj.to_s; 'to_s' end
23
- 'to_str' == LazyString.new { obj }.to_str or fail
24
- end.call
37
+ # LazyString#to_s should delegate to #to_str.
38
+ class ::Object
39
+ ls = LazyString.new
40
+ ls.instance_variable_set :@_test_to_str, test_to_str = Object.new
41
+ def ls.to_str
42
+ @_test_to_str
43
+ end
44
+ fail "" unless test_to_str.equal? ls.to_s
45
+ end
25
46
 
26
- lambda do
27
- obj = Object.new
28
- def obj.to_s; 'to_s' end
29
- !obj.respond_to?(:to_str) or fail
30
- 'to_s' == LazyString.new { obj }.to_str or fail
31
- end.call
47
+ # LazyString#to_str should return an empty string if the lazy string was made
48
+ # without a block.
49
+ fail "" unless "" == LazyString.new.to_str
32
50
 
33
- '42' == LazyString.new { 2 * 21 }.to_s or fail
51
+ # LazyString#to_str should convert the object returned by the saved proc to a
52
+ # string and return the result. If the object responds to to_str, the
53
+ # conversion should be done by sending that message.
54
+ class ::Object
55
+ block_result = Object.new
56
+ block_result.instance_variable_set :@_test_to_str, test_to_str = Object.new
57
+ def block_result.to_str
58
+ @_test_to_str
59
+ end
60
+ def block_result.to_s
61
+ "to_s"
62
+ end
63
+ fail "" unless test_to_str.equal? LazyString.new { block_result }.to_str
64
+ end
34
65
 
35
- lambda do
36
- arr = []
37
- ls = LazyString.new { arr << nil; 'foo' }
38
- ls.to_str
39
- 'foo' == ls.to_str or fail
40
- 1 == arr.length or fail
41
- end.call
66
+ # LazyString#to_str should convert the object returned by the saved proc to a
67
+ # string and return the result. If the object does not respond to to_str, the
68
+ # conversion should be done by sending to_s.
69
+ class ::Object
70
+ block_result = Object.new
71
+ block_result.instance_variable_set :@_test_to_s, test_to_s = Object.new
72
+ def block_result.to_s
73
+ @_test_to_s
74
+ end
75
+ fail "" unless test_to_s.equal? LazyString.new { block_result }.to_str
76
+ end
42
77
 
43
- lambda do
44
- ex = StandardError.new
45
- ls = LazyString.new { raise(ex) }
78
+ # After LazyString#to_str calls the saved proc as part of a successful string
79
+ # conversion, it should not call it again in subsequent invocations but return
80
+ # the same object.
81
+ class ::Object
82
+ calls = 0
83
+ ls = LazyString.new do
84
+ calls += 1
85
+ "string"
86
+ end
87
+ fail "" unless ls.to_str.equal? ls.to_str
88
+ fail "" unless 1 == calls
89
+ end
90
+
91
+ # LazyString#to_str should convert the object returned by the saved proc to a
92
+ # string and save the result. If that was successful, it should not convert the
93
+ # object again in subsequent invocations but return the same object.
94
+ class ::Object
95
+ block_result = Object.new
96
+ block_result.instance_variable_set :@_test_calls, 0
97
+ def block_result.to_s
98
+ @_test_calls += 1
99
+ "string"
100
+ end
101
+ ls = LazyString.new { block_result }
102
+ fail "" unless ls.to_str.equal? ls.to_str
103
+ fail "" unless 1 == block_result.instance_variable_get(:@_test_calls)
104
+ end
105
+
106
+ # LazyString#to_str should not save any result if converting to a string raised
107
+ # an exception.
108
+ class ::Object
109
+ block_result = Object.new
110
+ def block_result.to_s
111
+ raise RuntimeError
112
+ end
113
+ calls = 0
114
+ ls = LazyString.new do
115
+ calls += 1
116
+ block_result
117
+ end
118
+ ls.to_str rescue nil
119
+ ls.to_str rescue nil
120
+ fail "" unless 2 == calls
121
+ end
122
+
123
+ # LazyString#to_str and #to_s should propagate exceptions.
124
+ class ::Object
125
+ e = StandardError.new
126
+ ls = LazyString.new { ::Kernel.raise e }
46
127
  begin
47
128
  ls.to_str
48
129
  rescue
49
- ex.equal?($!) or fail
130
+ fail "" unless e.equal? $!
131
+ else
132
+ fail ""
133
+ end
134
+ begin
135
+ ls.to_s
136
+ rescue
137
+ fail "" unless e.equal? $!
50
138
  else
51
- fail
139
+ fail ""
52
140
  end
53
- end.call
141
+ end
142
+
143
+ # LazyString#to_str should raise an exception if any non-block arguments are
144
+ # sent.
145
+ begin
146
+ LazyString.new.to_str nil
147
+ rescue ArgumentError
148
+ else
149
+ fail ""
150
+ end
151
+
152
+ # LazyString#to_s should raise an exception if any non-block arguments are
153
+ # sent.
154
+ begin
155
+ LazyString.new.to_s nil
156
+ rescue ArgumentError
157
+ else
158
+ fail ""
159
+ end
54
160
 
55
- puts 'Test finished.'
161
+ # If this message doesn't get written, there was a problem.
162
+ puts "Test finished: #{__FILE__}"
metadata CHANGED
@@ -1,50 +1,73 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: lazy_string
3
- version: !ruby/object:Gem::Version
4
- version: 0.4.0
3
+ version: !ruby/object:Gem::Version
4
+ hash: 3
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
5
11
  platform: ruby
6
- authors:
12
+ authors:
7
13
  - Aaron Beckerman
8
- autorequire:
14
+ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
- date: 2022-11-13 00:00:00.000000000 Z
17
+
18
+ date: 2024-03-11 00:00:00 -07:00
19
+ default_executable:
12
20
  dependencies: []
13
- description: 'This library provides LazyString, a class for computing strings only
14
- when necessary. This is useful when computing the string is expensive but the string
15
- is unlikely to be used: an error message passed as an argument, for example.'
16
- email:
21
+
22
+ description: This library provides LazyString, a class for computing strings only when necessary. This is useful when computing the string is expensive but the string might never be used.
23
+ email:
17
24
  executables: []
25
+
18
26
  extensions: []
27
+
19
28
  extra_rdoc_files: []
20
- files:
29
+
30
+ files:
21
31
  - LICENSE.txt
22
32
  - README.txt
23
33
  - lazy_string.gemspec
24
34
  - lib/lazy_string.rb
25
35
  - test/lazy_string_test.rb
26
- homepage:
27
- licenses:
36
+ has_rdoc: true
37
+ homepage:
38
+ licenses:
28
39
  - MIT
29
- metadata: {}
30
- post_install_message:
40
+ post_install_message:
31
41
  rdoc_options: []
32
- require_paths:
42
+
43
+ require_paths:
33
44
  - lib
34
- required_ruby_version: !ruby/object:Gem::Requirement
35
- requirements:
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
36
48
  - - ">="
37
- - !ruby/object:Gem::Version
49
+ - !ruby/object:Gem::Version
50
+ hash: 57
51
+ segments:
52
+ - 1
53
+ - 8
54
+ - 7
38
55
  version: 1.8.7
39
- required_rubygems_version: !ruby/object:Gem::Requirement
40
- requirements:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
41
59
  - - ">="
42
- - !ruby/object:Gem::Version
43
- version: '0'
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
44
65
  requirements: []
45
- rubygems_version: 3.3.7
46
- signing_key:
47
- specification_version: 4
48
- summary: A Ruby library for lazily computing strings.
49
- test_files:
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.6.2
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: A class for computing strings only when necessary.
72
+ test_files:
50
73
  - test/lazy_string_test.rb
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA256:
3
- metadata.gz: b95d72633b9419e5306c154c7adda01b3ea723d39d4bf3ee58b41111371bc128
4
- data.tar.gz: 2fde23cece3bb04dec3570ab777fd8cf6528024dc1ead33ac2d6dae9d8fde974
5
- SHA512:
6
- metadata.gz: 5ea1f4d2c963a844fe677fdf59bf866b8ce33a323997357f243301640f79fb73dc15f45e7ff456db8274120de018a96d7aa36a5d782186299855ba9123e60699
7
- data.tar.gz: 375eb324a2af06e24b661eabce5e674420eb476f33a8165b457123dacb86fbf67148a391d8f24f4839e480b517f8d4be11899e8944283c570fc71e3e8da0de6d