lazy_string 0.4.0 → 0.8.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.
data/LICENSE.txt CHANGED
@@ -1,20 +1,19 @@
1
- Copyright (c) 2022 Aaron Beckerman
1
+ Copyright (c) 2012-2025 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/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,72 @@
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: 63
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 0
10
+ version: 0.8.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: 2025-05-16 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
- - lazy_string.gemspec
24
33
  - lib/lazy_string.rb
25
34
  - test/lazy_string_test.rb
26
- homepage:
27
- licenses:
35
+ has_rdoc: true
36
+ homepage:
37
+ licenses:
28
38
  - MIT
29
- metadata: {}
30
- post_install_message:
39
+ post_install_message:
31
40
  rdoc_options: []
32
- require_paths:
41
+
42
+ require_paths:
33
43
  - lib
34
- required_ruby_version: !ruby/object:Gem::Requirement
35
- requirements:
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
36
47
  - - ">="
37
- - !ruby/object:Gem::Version
48
+ - !ruby/object:Gem::Version
49
+ hash: 57
50
+ segments:
51
+ - 1
52
+ - 8
53
+ - 7
38
54
  version: 1.8.7
39
- required_rubygems_version: !ruby/object:Gem::Requirement
40
- requirements:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
41
58
  - - ">="
42
- - !ruby/object:Gem::Version
43
- version: '0'
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
44
64
  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:
50
- - test/lazy_string_test.rb
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.6.2
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: A class for computing strings only when necessary.
71
+ test_files: []
72
+
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
data/lazy_string.gemspec DELETED
@@ -1,19 +0,0 @@
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}
19
- end