string-builder 2.0.2 → 2.1.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 +4 -4
- data/README.md +166 -55
- data/Rakefile +5 -5
- data/lib/string/builder.rb +22 -2
- data/string-builder.gemspec +2 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eea962779b625fe78ef9c54a3806aff2550d6a9e3880387ada1fd7bdcacee075
|
4
|
+
data.tar.gz: c52ff6c81a88f7ac0b4f895dad393371fa66de4986526f9daa7f049206d5a532
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d6ed807bab2e597ea88d2c46b71db92710d634b58cecf964c26664f625c4b03976798e9892ee6c345a6342a379143aa09126d53c02942b6806785fc42c79aa8
|
7
|
+
data.tar.gz: 66dd1494d5fa8801c49d1e861f2f26f0635936e437b916b6bacbc7dd703d20932e94f765afb8bbeb13a47db8631d6cdcc980db18c2f548e61e6f945abaa795b4
|
data/README.md
CHANGED
@@ -4,69 +4,119 @@
|
|
4
4
|
|
5
5
|
# String::Builder
|
6
6
|
|
7
|
-
Modified port of the [String::Builder
|
7
|
+
Modified and extended port of the [String::Builder](https://crystal-lang.org/api/0.20.3/String/Builder.html#build%28capacity%3AInt%3D64%2C%26block%29%3AString-class-method) IO-style initializer from the `String` class of the Crystal programming language.
|
8
8
|
|
9
|
-
##
|
9
|
+
## Methods
|
10
10
|
|
11
|
-
|
11
|
+
There are three new methods in this extension of the `String` class:
|
12
12
|
|
13
|
-
|
13
|
+
### Instance methods
|
14
|
+
|
15
|
+
#### `String#build`
|
16
|
+
|
17
|
+
Takes a block yielding a new builder string, and appends the builder string to a duplicate of the original `String` object, `self`.
|
18
|
+
|
19
|
+
##### Examples
|
14
20
|
|
15
21
|
```ruby
|
16
|
-
|
17
|
-
|
18
|
-
s
|
19
|
-
s << 'World!'
|
20
|
-
s.string
|
22
|
+
foobar = 'foo'.build do |s|
|
23
|
+
s << 'bop'
|
24
|
+
s.gsub!('op','ar')
|
21
25
|
end
|
22
|
-
|
26
|
+
|
27
|
+
foobar #=> "foobar"
|
23
28
|
```
|
24
29
|
|
25
|
-
|
30
|
+
```ruby
|
31
|
+
foo = 'foo'
|
32
|
+
|
33
|
+
foobar = foo.build do |s|
|
34
|
+
s << 'bop'
|
35
|
+
s.gsub!('op','ar')
|
36
|
+
end
|
37
|
+
|
38
|
+
foobar #=> "foobar"
|
39
|
+
```
|
40
|
+
|
41
|
+
#### `String#build!`
|
42
|
+
|
43
|
+
Takes a block yielding a new builder string, and appends the builder string to the original `String` object, `self`.
|
44
|
+
|
45
|
+
**NOTE**: This mutates the original string, as indicated by the bang `!`.
|
46
|
+
|
47
|
+
##### Example
|
26
48
|
|
27
49
|
```ruby
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
s <<
|
50
|
+
foobar = 'foo'
|
51
|
+
|
52
|
+
foobar.build! do |s|
|
53
|
+
s << 'bop'
|
54
|
+
s.gsub!('op','ar')
|
32
55
|
end
|
33
|
-
|
56
|
+
|
57
|
+
foobar #=> "foobar"
|
34
58
|
```
|
35
59
|
|
36
|
-
|
60
|
+
### Class methods
|
37
61
|
|
38
|
-
|
62
|
+
#### `String.build`
|
63
|
+
|
64
|
+
Takes an arbitrary object and a block yielding a new string builder, and appends the builder string to a duplicate of the object parameter converted to a string (with `to_s`).
|
65
|
+
|
66
|
+
If no block is given, then the object converted to a string (with `to_s`) is returned.
|
67
|
+
|
68
|
+
##### Examples
|
39
69
|
|
40
70
|
```ruby
|
41
|
-
|
42
|
-
|
43
|
-
s
|
44
|
-
s << 'World!'
|
45
|
-
s.upcase!
|
46
|
-
s.string
|
71
|
+
foobar = String.build 'foo' do |s|
|
72
|
+
s << 'bop'
|
73
|
+
s.gsub!('op','ar')
|
47
74
|
end
|
48
|
-
|
75
|
+
|
76
|
+
foobar #=> "foobar"
|
49
77
|
```
|
50
78
|
|
51
79
|
```ruby
|
52
|
-
|
53
|
-
|
54
|
-
s
|
55
|
-
s << "World!"
|
56
|
-
s.gsub!("!", "?")
|
80
|
+
foobar = String.build 3 do |s|
|
81
|
+
s << 'bop'
|
82
|
+
s.gsub!('op','ar')
|
57
83
|
end
|
58
|
-
|
84
|
+
|
85
|
+
foobar #=> "3bar"
|
59
86
|
```
|
60
87
|
|
61
|
-
|
88
|
+
```ruby
|
89
|
+
foo = 'foo'
|
90
|
+
|
91
|
+
foobar = String.build foo do |s|
|
92
|
+
s << 'bop'
|
93
|
+
s.gsub!('op','ar')
|
94
|
+
end
|
62
95
|
|
63
|
-
|
96
|
+
foobar #=> "foobar"
|
97
|
+
foo #=> "foo"
|
98
|
+
```
|
99
|
+
|
100
|
+
## Detailed example
|
64
101
|
|
65
102
|
This example shows how to make a simple logger by constructing log messages with `String::Builder`.
|
66
103
|
|
67
|
-
|
68
|
-
|
69
|
-
|
104
|
+
Suppose we want a `Logger` class that allows us to do the following:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
logger = Logger.new
|
108
|
+
|
109
|
+
logger.error 'String::Builder is good?'
|
110
|
+
#=> [03:54:53s] (lib/string-builder.rb) ERROR » String::Builder is good!
|
111
|
+
logger.success 'String::Builder is good?'
|
112
|
+
#=> [03:54:55s] (lib/string-builder.rb) SUCCESS » String::Builder is good!
|
113
|
+
logger.info 'String::Builder is good?'
|
114
|
+
#=> [03:54:57s] (lib/string-builder.rb) INFO » String::Builder is good!
|
115
|
+
logger.warning 'String::Builder is good?'
|
116
|
+
#=> [03:54:59s] (lib/string-builder.rb) WARNING » String::Builder is good!
|
117
|
+
```
|
118
|
+
|
119
|
+
### Class method - `String.build`
|
70
120
|
|
71
121
|
```ruby
|
72
122
|
require 'string/builder'
|
@@ -75,28 +125,37 @@ class Logger
|
|
75
125
|
using String::Builder
|
76
126
|
%i[error success info warning].each do |severity|
|
77
127
|
define_method(severity) do |message|
|
78
|
-
|
79
|
-
|
80
|
-
s << "
|
81
|
-
s.
|
128
|
+
time = Time.now.strftime("[%H:%M:%Ss]")
|
129
|
+
String.build time do |s|
|
130
|
+
s << " (#{__FILE__})"
|
131
|
+
s << " #{severity.to_s.upcase} » #{message}"
|
132
|
+
s.gsub!('?','!')
|
82
133
|
end
|
83
134
|
end
|
84
135
|
end
|
85
136
|
end
|
137
|
+
```
|
86
138
|
|
87
|
-
|
88
|
-
|
89
|
-
logger.error 'String::Builder is good?'
|
90
|
-
#=> [03:54:53s] (lib/string-builder.rb) ERROR » String::Builder is good!
|
139
|
+
### Instance method - `String#build`
|
91
140
|
|
92
|
-
|
93
|
-
#=> [03:54:55s] (lib/string-builder.rb) SUCCESS » String::Builder is good!
|
141
|
+
The class shown above can use the `String#build` instance method to achieve the same functionality.
|
94
142
|
|
95
|
-
|
96
|
-
|
143
|
+
```ruby
|
144
|
+
require 'string/builder'
|
97
145
|
|
98
|
-
|
99
|
-
|
146
|
+
class Logger
|
147
|
+
using String::Builder
|
148
|
+
%i[error success info warning].each do |severity|
|
149
|
+
define_method(severity) do |message|
|
150
|
+
time = Time.now.strftime("[%H:%M:%Ss]")
|
151
|
+
time.build do |s|
|
152
|
+
s << " (#{__FILE__})"
|
153
|
+
s << " #{severity.to_s.upcase} » #{message}"
|
154
|
+
s.gsub!('?','!')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
100
159
|
```
|
101
160
|
|
102
161
|
## Installation
|
@@ -117,26 +176,78 @@ Or install it yourself as:
|
|
117
176
|
|
118
177
|
## Usage
|
119
178
|
|
120
|
-
This
|
179
|
+
This extension is in the form of a `refinement`. This means that you will have to call the following `using` directive within the scope that you want the `String` class to be extended with `String::Builder` methods:
|
121
180
|
|
122
181
|
```ruby
|
123
182
|
require 'string/builder'
|
124
183
|
using String::Builder
|
125
184
|
```
|
126
185
|
|
127
|
-
Though you should typically avoid doing this in the global scope (unless you really need to), and instead only use the
|
186
|
+
Though you should typically avoid doing this in the global scope (unless you really need to), and instead only use the extension where you need it - inside your specific modules or classes:
|
128
187
|
|
129
188
|
```ruby
|
130
189
|
require 'string/builder'
|
131
190
|
|
132
191
|
class A
|
133
192
|
using String::Builder
|
134
|
-
# CAN use String
|
193
|
+
# CAN use String::Builder methods in this class
|
135
194
|
end
|
136
195
|
|
137
196
|
module B
|
138
|
-
# CANNOT use String
|
197
|
+
# CANNOT use String::Builder methods in this module
|
198
|
+
end
|
199
|
+
|
200
|
+
# CANNOT use String::Builder methods in the global scope
|
201
|
+
```
|
202
|
+
|
203
|
+
## Limitations of string building in Ruby and Crystal
|
204
|
+
|
205
|
+
The [String::Builder](https://crystal-lang.org/api/0.20.3/String/Builder.html) class of the Crystal programming language provides an initializer method for the `String` class called `build` which is essentially an optimized version of Ruby's `StringIO`.
|
206
|
+
|
207
|
+
Ruby's `StringIO` and Crystal's `String::Builder` are great because it essentially turns strings into IO objects, allowing you to pass a block into the constructor (yielding `self`) which leads to nice chaining such as:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
# Ruby - StringIO
|
211
|
+
test = StringIO.open do |s|
|
212
|
+
s << 'Hello '
|
213
|
+
s << 'World!'
|
214
|
+
s.string
|
139
215
|
end
|
216
|
+
#=> "Hello World!"
|
217
|
+
```
|
218
|
+
|
219
|
+
Note the necessary `StringIO#string` method call. Since we are yielding a `StringIO` object, we must convert it to a `String` at the end. This is a bit cleaner in Crystal:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
# Crystal - String::Builder
|
223
|
+
test = String.build do |s|
|
224
|
+
s << "Hello "
|
225
|
+
s << "World!"
|
226
|
+
end
|
227
|
+
#=> "Hello World!"
|
228
|
+
```
|
140
229
|
|
141
|
-
|
230
|
+
---
|
231
|
+
|
232
|
+
However, since **neither** of these two implementations yield a `String` object, you can't use `String` methods to mutate the object:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
# Ruby - StringIO
|
236
|
+
test = StringIO.open do |s|
|
237
|
+
s << 'Hello '
|
238
|
+
s << 'World!'
|
239
|
+
s.upcase!
|
240
|
+
s.string
|
241
|
+
end
|
242
|
+
#=> ... undefined method `upcase!' for #<StringIO:0x00007fe0bc09d810> (NoMethodError)
|
243
|
+
```
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
# Crystal - String::Builder
|
247
|
+
test = String.build do |s|
|
248
|
+
s << "Hello "
|
249
|
+
s << "World!"
|
250
|
+
s.gsub!("!", "?")
|
251
|
+
end
|
252
|
+
#=> ... undefined method 'gsub!' for String::Builder
|
142
253
|
```
|
data/Rakefile
CHANGED
data/lib/string/builder.rb
CHANGED
@@ -1,12 +1,32 @@
|
|
1
1
|
module String::Builder
|
2
2
|
refine String.singleton_class do
|
3
|
+
|
3
4
|
def build(obj = String.new)
|
4
5
|
return obj.to_s unless block_given?
|
5
6
|
yield builder = self.new
|
6
7
|
obj.dup.to_s << builder
|
7
8
|
end
|
8
|
-
|
9
|
-
|
9
|
+
|
10
|
+
def respond_to?(id, private = false)
|
11
|
+
id.to_sym == :build ? true : super
|
10
12
|
end
|
13
|
+
|
14
|
+
end
|
15
|
+
refine String do
|
16
|
+
|
17
|
+
def build
|
18
|
+
yield builder = String.new
|
19
|
+
self.dup << builder
|
20
|
+
end
|
21
|
+
|
22
|
+
def build!
|
23
|
+
yield builder = String.new
|
24
|
+
self << builder
|
25
|
+
end
|
26
|
+
|
27
|
+
def respond_to?(id, private = false)
|
28
|
+
%i[build build!].include?(id.to_sym) ? true : super
|
29
|
+
end
|
30
|
+
|
11
31
|
end
|
12
32
|
end
|
data/string-builder.gemspec
CHANGED
@@ -3,11 +3,11 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "string-builder"
|
6
|
-
spec.version = "2.0
|
6
|
+
spec.version = "2.1.0"
|
7
7
|
spec.authors = ["Edwin Onuonga"]
|
8
8
|
spec.email = ["edwinonuonga@gmail.com"]
|
9
9
|
|
10
|
-
spec.summary = %q{Modified port of the String::Builder IO initializer
|
10
|
+
spec.summary = %q{Modified and extended port of the String::Builder IO-style initializer from the String class of the Crystal programming language.}
|
11
11
|
spec.homepage = "https://www.github.com/eonu/string-builder"
|
12
12
|
spec.license = "MIT"
|
13
13
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: string-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edwin Onuonga
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -93,6 +93,6 @@ rubyforge_project:
|
|
93
93
|
rubygems_version: 2.7.3
|
94
94
|
signing_key:
|
95
95
|
specification_version: 4
|
96
|
-
summary: Modified port of the String::Builder IO initializer
|
97
|
-
of the Crystal programming language.
|
96
|
+
summary: Modified and extended port of the String::Builder IO-style initializer from
|
97
|
+
the String class of the Crystal programming language.
|
98
98
|
test_files: []
|