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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47bae59709088183dfce8b8b556c1363234b8b0c57e91c50cec51a6def01675f
4
- data.tar.gz: 1ffccd0dcbb9cb5dad6480e63618ba24b9c49591503271e13ad8fe4b0f0e1eb6
3
+ metadata.gz: eea962779b625fe78ef9c54a3806aff2550d6a9e3880387ada1fd7bdcacee075
4
+ data.tar.gz: c52ff6c81a88f7ac0b4f895dad393371fa66de4986526f9daa7f049206d5a532
5
5
  SHA512:
6
- metadata.gz: 93b5c440450e88eab450d79c4a67cccaa1038c5d6347e5bc7ec9d9a87879d8e56573794f8849b0487b8222aa1fc08b59b9231a55fe50ab9f1c2a80a556233d09
7
- data.tar.gz: 97fe5c373cf15b819a0d1fc880f2a125b4af42b524c2d919417a2471288e45b42ede0cb7dc421fffbebb0ae6bb6574717274be59a5d780ff627c92b2b03c9380
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 IO initializer](https://crystal-lang.org/api/0.20.3/String/Builder.html#build%28capacity%3AInt%3D64%2C%26block%29%3AString-class-method) for the String class of the Crystal programming language.
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
- ## Limitations of string building in Ruby and Crystal
9
+ ## Methods
10
10
 
11
- 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`.
11
+ There are three new methods in this extension of the `String` class:
12
12
 
13
- 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:
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
- # Ruby - StringIO
17
- test = StringIO.open do |s|
18
- s << 'Hello '
19
- s << 'World!'
20
- s.string
22
+ foobar = 'foo'.build do |s|
23
+ s << 'bop'
24
+ s.gsub!('op','ar')
21
25
  end
22
- #=> "Hello World!"
26
+
27
+ foobar #=> "foobar"
23
28
  ```
24
29
 
25
- 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:
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
- # Crystal - String::Builder
29
- test = String.build do |s|
30
- s << "Hello "
31
- s << "World!"
50
+ foobar = 'foo'
51
+
52
+ foobar.build! do |s|
53
+ s << 'bop'
54
+ s.gsub!('op','ar')
32
55
  end
33
- #=> "Hello World!"
56
+
57
+ foobar #=> "foobar"
34
58
  ```
35
59
 
36
- ---
60
+ ### Class methods
37
61
 
38
- However, since neither of these two implementations yield a `String` object, you can't use `String` methods to mutate the object:
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
- # Ruby - StringIO
42
- test = StringIO.open do |s|
43
- s << 'Hello '
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
- #=> ... undefined method `upcase!' for #<StringIO:0x00007fe0bc09d810> (NoMethodError)
75
+
76
+ foobar #=> "foobar"
49
77
  ```
50
78
 
51
79
  ```ruby
52
- # Crystal - String::Builder
53
- test = String.build do |s|
54
- s << "Hello "
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
- #=> ... undefined method 'gsub!' for String::Builder
84
+
85
+ foobar #=> "3bar"
59
86
  ```
60
87
 
61
- **That's where this gem comes in!**
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
- ## Example
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
- > **NOTE**:
68
- > - You can pass an optional argument before the block, specifying what the starting string (or any object that has a working `to_s` method) should be.
69
- > - Since the block `yield`s a `String` object, `String::Builder` allows you to mutate the string itself as seen in this example with the `String#gsub!` method.
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
- String.build Time.now.strftime("[%H:%M:%Ss] ") do |s|
79
- s << "(#{__FILE__}) "
80
- s << "#{severity.to_s.upcase} » #{message}"
81
- s.gsub! '?', '!'
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
- logger = Logger.new
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
- logger.success 'String::Builder is good?'
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
- logger.info 'String::Builder is good?'
96
- #=> [03:54:57s] (lib/string-builder.rb) INFO » String::Builder is good!
143
+ ```ruby
144
+ require 'string/builder'
97
145
 
98
- logger.warning 'String::Builder is good?'
99
- #=> [03:54:59s] (lib/string-builder.rb) WARNING » String::Builder is good!
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 monkey-patch 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.build` class method to be monkey-patched into the `String` class:
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 monkey-patch where you need it - inside your specific modules or classes:
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.build in this class
193
+ # CAN use String::Builder methods in this class
135
194
  end
136
195
 
137
196
  module B
138
- # CANNOT use String.build in this module
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
- # CANNOT use String.build in the global scope
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
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
1
  task :default => :spec
2
+
3
+ desc "Runs specs"
4
+ task :spec do
5
+ sh "rspec -fd spec"
6
+ end
@@ -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
- def respond_to?(symbol, include_all = false)
9
- self.methods(false).dup.<<(:build).include?(symbol)
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
@@ -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.2"
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 for the String class of the Crystal programming language.}
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.2
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-05 00:00:00.000000000 Z
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 for the String class
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: []