string-builder 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []