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 +16 -17
- data/README.txt +14 -29
- data/lazy_string.gemspec +13 -18
- data/lib/lazy_string.rb +26 -26
- data/test/lazy_string_test.rb +145 -38
- metadata +51 -28
- checksums.yaml +0 -7
data/LICENSE.txt
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2024 Aaron Beckerman
|
2
2
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
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
|
5
|
-
used
|
4
|
+
useful when computing the string is expensive but the string might never be
|
5
|
+
used.
|
6
6
|
|
7
|
-
Thanks to duck typing and
|
8
|
-
|
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
|
14
|
-
|
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
|
19
|
-
But later, if
|
20
|
-
called with no arguments
|
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
|
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
|
26
|
-
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
#
|
3
|
-
|
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.
|
14
|
-
#
|
15
|
-
#
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@
|
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
|
-
#
|
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
|
-
#
|
30
|
-
# arguments
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
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
|
38
|
-
|
39
|
-
|
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
|
data/test/lazy_string_test.rb
CHANGED
@@ -1,55 +1,162 @@
|
|
1
|
-
|
1
|
+
# Sections that create local variables are in class definitions so that later
|
2
|
+
# sections cannot accidentally reference those local variables.
|
2
3
|
|
3
|
-
|
4
|
+
require "lazy_string"
|
4
5
|
|
5
|
-
|
6
|
+
# LazyString should be a class.
|
7
|
+
fail "" unless Class.equal? LazyString.class
|
6
8
|
|
7
|
-
|
8
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
17
|
+
|
18
|
+
date: 2024-03-11 00:00:00 -07:00
|
19
|
+
default_executable:
|
12
20
|
dependencies: []
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
-
|
27
|
-
|
36
|
+
has_rdoc: true
|
37
|
+
homepage:
|
38
|
+
licenses:
|
28
39
|
- MIT
|
29
|
-
|
30
|
-
post_install_message:
|
40
|
+
post_install_message:
|
31
41
|
rdoc_options: []
|
32
|
-
|
42
|
+
|
43
|
+
require_paths:
|
33
44
|
- lib
|
34
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
-
|
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
|
-
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
41
59
|
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
44
65
|
requirements: []
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|