finishing_moves 0.3.1 → 0.4.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
  SHA1:
3
- metadata.gz: a2995e11dcd05cd279e8b42f1d7cbf12fc985ca9
4
- data.tar.gz: 1ff68edd10b08e64895ad3ae8bf7cb4aa8cf1c05
3
+ metadata.gz: 071f7f2b9b87bc0af4db17b2d7446280677de657
4
+ data.tar.gz: 6ae3e34b857d2c35dd6fb22051296955c95d4f26
5
5
  SHA512:
6
- metadata.gz: 94d28dfbf4dc1a6fda6ba9f89badedfb4fdcac1f67b6b0664d4e294c6f9631a132d0e63386a1eb9e527b5a65e38a036b024c86c9b1b9ab6fde723ebda13ff97a
7
- data.tar.gz: 68df39eccec46a3c72f03f0d15ef28507d091eedfb4240e1a8714409adb53d67d12d2b7b5d4951c171c51c286df4294e1b84fa43b33687020df96d7b9b71e491
6
+ metadata.gz: ba0d30ea178be6cafc8df93a981557fb0087fc95a5569276577c25b33bc524eb041348f4202ea4e9aae1b6bac688aee1b14b3688b748933fb2d7dcbeec42027d
7
+ data.tar.gz: 2b4e2b32b5dbd18673e620888b2464f6c26f117d500526a804f693d53d25da322577754b2ab3928b54caac21f8411c17a56e1f3fa8b981b222b6217bf4da88a8
data/.gitignore CHANGED
@@ -29,9 +29,9 @@ build/
29
29
 
30
30
  # for a library or gem, you might want to ignore these files since the code is
31
31
  # intended to run in multiple environments; otherwise, check them in:
32
- # Gemfile.lock
33
- # .ruby-version
34
- # .ruby-gemset
32
+ Gemfile.lock
33
+ .ruby-version
34
+ .ruby-gemset
35
35
 
36
36
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
37
  .rvmrc
data/.travis.yml CHANGED
@@ -3,10 +3,10 @@ language: ruby
3
3
  cache: bundler
4
4
 
5
5
  rvm:
6
- - 1.9.3
7
6
  - 2.0.0
8
7
  - 2.1.0
9
8
  - 2.2.0
9
+ - 2.2.1
10
10
  - ruby-head
11
11
 
12
12
  script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,19 +1,11 @@
1
1
  # Finishing Moves
2
2
  [![Gem Version](https://badge.fury.io/rb/finishing_moves.svg)](http://badge.fury.io/rb/finishing_moves)
3
-
4
- ##### By the guys at [Forge Software](http://www.forgecrafted.com/)
3
+ [![Build Status](https://travis-ci.org/forgecrafted/finishing_moves.svg?branch=master)](https://travis-ci.org/forgecrafted/finishing_moves.svg?branch=master)
4
+ [![Hire Us!](https://img.shields.io/badge/biz-hire%20us!-F7931E.svg)](http://www.forgecrafted.com)
5
5
 
6
6
  Ruby includes a huge amount of default awesomeness that tackles most common development challenges. But every now and then, you find yourself in a situation where an **elaborate-yet-precise** coding maneuver wins the day. Finishing Moves is a collection of methods designed to assist in those just-typical-enough-to-be-annoying scenarios.
7
7
 
8
- In gamer terms, if standard Ruby methods are your default moves, `finishing_moves` would be mana-consuming techniques. Your cooldown spells. Your grenades (there's never enough grenades!). In the right situation, they kick serious [cyclomatic butt](https://en.wikipedia.org/wiki/Cyclomatic_complexity).
9
-
10
- ## Development approach
11
-
12
- - **Never** override default Ruby behavior, only add functionality.
13
- - Follow the Unix philosophy of *"Do one job really well."*
14
- - Minimize assumptions, e.g. avoid formatting output, mutating values, and long conditional logic flows.
15
- - Play nice with major Ruby players like Rake, Rails, and Sinatra.
16
- - Test all the things.
8
+ In gamer terms, if standard Ruby methods are your default moves, Finishing Moves would be mana-consuming techniques. Your cooldown spells. Your grenades (there's never enough grenades!). In the right situation, they kick serious [cyclomatic butt](https://en.wikipedia.org/wiki/Cyclomatic_complexity).
17
9
 
18
10
  ## Installation
19
11
 
@@ -27,1163 +19,50 @@ Command line
27
19
  gem install 'finishing_moves'
28
20
  ```
29
21
 
30
- [Here's the gem link](https://rubygems.org/gems/finishing_moves), if you like looking at that stuff.
31
-
32
- ## List of Methods
33
-
34
- - [`Kernel#nil_chain`](#kernelnil_chain)
35
- - [`Kernel#cascade`](#kernelcascade)
36
- - [`Kernel#class_exists?`](#kernelclass_exists)
37
- - [`Object#same_as`](#objectsame_as)
38
- - [`Object#not_nil?`](#objectnot_nil)
39
- - [`Hash#delete!`](#hashdelete)
40
- - [`Hash#delete_each`](#hashdelete_each)
41
- - [`Hash#delete_each!`](#hashdelete_each-1)
42
- - [`Integer#length`](#integerlength)
43
- - [`Boolean` Typecasting](#typecasting-to-boolean)
44
-
45
- ###### *New in 0.3.0!*
46
-
47
- - [`Object#is_an?`](#objectis_an)
48
- - [`Array#to_hash_values`](#arrayto_hash_values)
49
- - [`Array#to_indexed_hash`](#arrayto_indexed_hash)
50
- - [`Array#to_hash_keys`](#arrayto_hash_keys)
51
- - [`Enumerable#key_map`](#enumerablekey_map)
52
- - [`Enumerable#key_map_reduce`](#enumerablekey_map_reduce)
53
- - [`String#dedupe`](#stringdedupe)
54
- - [`String#keyify`](#stringkeyify)
55
- - [`String#match?`](#stringmatch)
56
- - [`String#nl2br`](#stringnl2br)
57
- - [`String#remove_whitespace`](#stringremove_whitespace)
58
- - [`String#strip_all`](#stringstrip_all)
59
-
60
- ### Extensions to `Kernel`
61
-
62
- #### `Kernel#nil_chain`
63
- ###### `nil_chain(ret_val = nil, &block)`
64
-
65
- Arguably the sharpest knife in the block, `#nil_chain` allows you to write elaborate method chains without fear of tripping over `NoMethodError` and `NameError` exceptions when something in the chain throws out a nil value.
66
-
67
- ##### Examples
68
-
69
- ```ruby
70
- # foobar may have a transmogrify method...or it may not! Doooooom!
71
-
72
- # without nil_chain, we check to make sure the method exists
73
-
74
- foobar.transmogrify if foobar.respond_to? :transmogrify
75
-
76
- # with nil_chain, we just do it, and kick those nil ghosts in the teeth
77
-
78
- nil_chain{ foobar.transmogrify }
79
- # => result of foobar.transmogrify, or nil
80
- ```
81
-
82
- Not really saving much typing there, but how about an object assigned to a hash?
83
-
84
- ```ruby
85
- # without nil_chain, we check to make sure the key exists
86
-
87
- if my_hash.has_key? :foo
88
- my_hash[:foo].do_stuff
89
- end
90
-
91
- # with nil_chain, things look a lot cleaner
92
-
93
- nil_chain{ my_hash[:foo].do_stuff }
94
- # => result of my_hash[:foo].do_stuff, or nil
95
- ```
96
-
97
- Still pretty simple. Let's try it on a series of connected objects.
98
-
99
- ```ruby
100
- class A
101
- attr_accessor :b
102
- def initialize(b)
103
- @b = b
104
- end
105
- end
106
-
107
- class B
108
- attr_accessor :c
109
- def initialize(c)
110
- @c = c
111
- end
112
- end
113
-
114
- class C
115
- def hello
116
- "Hello, world!"
117
- end
118
- end
119
-
120
- c = C.new
121
- b = B.new c
122
- a = A.new b
123
-
124
- a.b.c.hello
125
- # => "Hello, world!"
126
- ```
127
-
128
- Let's suppose the presence of attribute `c` is conditional. We must then check for a proper association between objects `b` and `c` before calling `hello`.
129
-
130
- ```ruby
131
- b.c = nil
132
- a.b.c.hello
133
- # => NoMethodError: undefined method `hello' for nil:NilClass
134
-
135
- a.b.c.hello unless b.c.nil? || b.c.empty?
136
- # => nil
137
-
138
- a.b = nil
139
-
140
- # Now it's really getting ugly.
141
- if !a.b.nil? && !a.b.empty?
142
- a.b.c.hello unless b.c.nil? || b.c.empty?
143
- end
144
-
145
- # Imagine if we had a fourth association, or a fifth! The patterns, man!
146
- ```
147
-
148
- Or we can just skip all that conditional nonsense.
149
-
150
- ```ruby
151
- nil_chain{ a.b.c.hello }
152
- # => output "Hello, world!" or nil
153
-
154
- a = nil
155
- nil_chain{ a.b.c.hello }
156
- # => still just nil
157
- ```
158
-
159
- ##### Examples in Rails
160
-
161
- We use `nil_chain` all the time in Rails projects. The A-B-C class example above was derived from a frequent use case in our models...
162
-
163
- ```ruby
164
- # Model User has ZERO or more addresses, one of which is the primary.
165
- # Model Address has a zip_code attribute.
166
-
167
- user = User.find(9876)
168
- nil_chain{ user.addresses.primary.zip_code }
169
- # => returns nil if no addresses, or primary not set, otherwise returns zip_code
170
- ```
171
-
172
- It also helps when dealing with optional parameters coming in from forms...
173
-
174
- ```ruby
175
- # Somewhere in a random rails controller...
176
-
177
- def search
178
- case nil_chain { params[:case_state].downcase }
179
- when 'open' then filter_only_open
180
- when 'closed' then filter_only_closed
181
- when 'invalid' then filter_only_invalid
182
- when 'withdrawn' then filter_only_withdrawn
183
- when 'canceled' then filter_only_canceled
184
- end
185
- # => apply a case state filter, or do nothing
186
- end
187
- ```
188
-
189
- Setting default values on form inputs in views...
190
-
191
- ```ruby
192
- select_tag :date_field,
193
- options_for_select(@dropdown_date_field, nil_chain{params[:date_field]} )
194
- # => Sets the selected option in the dropdown if the :date_field parameter exists
195
- ```
196
-
197
- ##### Custom return value
198
-
199
- You can change the value that `nil_chain` returns when it catches a `NoMethodError` or `NameError` exception. `nil_chain` accepts a single optional argument before the block to represent the return value. The default is `nil`, but you can set it to whatever you want.
200
-
201
- We recently used this functionality in generating a CSV report. The client's use case required us to spit out an `'N/A'` string anytime a proper field value was missing. `nil_chain` made the adjustment easy.
202
-
203
- ```ruby
204
- CSV.generate do |csv|
205
- @records.each do |record| # each record represents a single line in the CSV
206
- values = []
207
- csv_fields_in_order.each do |field|
208
- values << nil_chain('N/A') { record.send(field) }
209
- # respond with a pretty value when the field is empty or invalid
210
- end
211
- csv << values
212
- end
213
- end
214
- ```
215
-
216
- We also find this handy when doing conditional stuff based on presence/absence of a key in a hash.
217
-
218
- ```ruby
219
- # without nil_chain
220
- if my_hash[:foo]
221
- # (by default, ruby returns nil when you request an unset key)
222
- var = my_hash[:foo]
223
- else
224
- var = :default_value
225
- end
226
-
227
- # with nil_chain, we get a nice one liner
228
- var = nil_chain(:default_value) { my_hash[:foo] }
229
-
230
- # What if the default value is coming from somewhere else?
231
- # What if we want to call a method directly on the hash?
232
- # What if the ley lines are out of alignment!?
233
- # No problem.
234
-
235
- var = nil_chain(Geomancer.reset_ley_lines) { summon_fel_beast[:step_3].scry }
236
- # => value of summon_fel_beast[:step_3].scry if it's set, or
237
- # Geomancer.reset_ley_lines if it's not
238
- ```
239
-
240
- ##### Alias
241
-
242
- `nil_chain` is aliased to `method_chain` for alternative clarity.
243
-
244
- #### `Kernel#bool_chain`
245
-
246
- This is the same logic under the hood as `nil_chain`, however we forcibly return a boolean `false` instead of `nil` if the chain breaks.
247
-
248
- Following our A-B-C example above...
249
-
250
- ```ruby
251
- bool_chain{ a.b.c.hello }
252
- # => false
253
- ```
254
-
255
- #### `Kernel#class_exists?`
256
-
257
- Sure, Ruby has the `defined?` method, but the output is less than helpful when you're doing conditional flows.
258
-
259
- ```ruby
260
- defined?(SuperSaiyan)
261
- # => nil
262
-
263
- require 'super_saiyan'
264
-
265
- defined?(SuperSaiyan)
266
- # => 'constant'
267
-
268
- if defined?(SuperSaiyan) == 'constant'
269
- # Power up to level 4
270
- # But after that obtuse if-statement, I'm just too tired
271
- end
272
- ```
273
-
274
- `class_exists?` does exactly what you want, and provides an obvious, natural boolean response.
275
-
276
- ```ruby
277
- class_exists? :Symbol
278
- # => true
279
- class_exists? :Symbology
280
- # => false, unless you're Dan Brown
281
- class_exists? :Rails
282
- # => true in a Rails app
283
- ```
284
-
285
- Because the class **might** exist, we cannot pass in the constant version of the name. You **must** use a symbol or string value.
286
-
287
- ```ruby
288
- class_exists? DefinitelyFakeClass
289
- # => NameError: uninitialized constant DefinitelyFakeClass
290
-
291
- class_exists? :DefinitelyFakeClass
292
- # => false (at least it better be; if you *actually* use this name, I will find you...)
293
- ```
294
-
295
- #### `Kernel#cascade`
296
-
297
- This method is designed to facilitate a set of **consecutive, mutating actions** which may be interrupted at multiple arbitrary points. In pseudo-code, the logic we're trying to write looks like this:
298
-
299
- 1. Begin stepwise process.
300
- 2. Set `[values]` to a default starting state.
301
- 3. If `[first requirement]` is not met, bail out.
302
- 4. Perform steps that require `[first requirement]`, possibly mutating `[values]`.
303
- 5. If `[next requirement]` is not met, bail out.
304
- 6. Perform steps that require `[next requirement]`, possibly mutating `[values]` again.
305
- 7. (Repeat for as many steps as necessary.)
306
- 8. End stepwise process.
307
- 9. Perform follow-up action(s) based on resulting `[values]`.
308
-
309
- Here's a contrived Rails-y sample of a login approval process:
310
-
311
- ```ruby
312
- cascade do
313
- logged_in = false
314
- # not doing anything if they didn't provide creds
315
- break if params['username'].nil? || params['password'].nil?
316
- # ok, got creds, do they exist?
317
- user = User.find_by username: params['username']
318
- # does the user exist?
319
- break if user.nil?
320
- # does the password match?
321
- break if user.validate_password(params['password'])
322
- # maybe the user account is banned?
323
- break if user.banned?
324
- # everything looks good, let's do it
325
- login user
326
- logged_in = true
327
- end
328
-
329
- if logged_in
330
- # additional follow-up steps for authenticated users
331
- else
332
- # display error message, log the failed attempt, whatever
333
- end
334
- ```
335
-
336
- We're using the [`loop`](http://www.ruby-doc.org/core-2.1.5/Kernel.html#method-i-loop) construct under the hood, which is what allows us to use the `break` statement as outlined in the example.
337
-
338
- ###### *"Why not just shove the logic into a method and use `return` instead of `break`?"*
339
-
340
- You should absolutely use methods if it makes sense!
341
-
342
- `cascade` is ideal for small sets of logic, when you've *already* broken out your logic into a method and further breakout is just silly.
343
-
344
- To illustrate, here's a small real-world sample from one of our projects:
345
-
346
- ```ruby
347
- class ReportsController < ApplicationController
348
-
349
- before_action :define_search_params, only: :run_report
350
-
351
- # ...
352
-
353
- def define_search_params
354
- @report = params[:report].to_sym
355
-
356
- # Set the report category, :medical or :drug
357
- # 1. An :ongoing report is always in the :drug category
358
- # 2. Otherwise default to :medical
359
- # 3. :dismissal reports are always :medical (so we use the default)
360
- # 4. Finally just use the params value, if it matches an allowable value
361
- cascade do
362
- if @report == :ongoing
363
- @category = :drug
364
- break
365
- end
366
- @category = :medical
367
- break if @report == :dismissals
368
- @category = params[:category] if params[:category].in? allowable_categories
369
- end
370
- end
371
-
372
- end
373
- ```
374
-
375
- It's overkill to break that bit of logic for the value of `@category` out into another method.
376
-
377
- Plus, we find the vertically aligned codes reads better, especially as the list of conditionals goes beyond two. This pattern also has the added benefit of making top-to-bottom "readable" sense.
378
-
379
- ### Extensions to `Object`
380
-
381
- #### `Object#same_as`
382
-
383
- Comparison operator that normalizes both sides into strings, then runs them over `==`.
384
-
385
- The comparison will work on any class that has a `to_s` method defined on it.
386
-
387
- ```ruby
388
- # All these comparisons will return true
389
-
390
- :foobar.same_as 'foobar'
391
- 'foobar'.same_as :foobar
392
- '1'.same_as 1
393
- 2.same_as '2'
394
- 3.same_as 3
395
- ```
396
-
397
- Normal case-sensitivity rules apply.
398
-
399
- ```ruby
400
- :symbol.same_as :SYMBOL
401
- # => false
402
-
403
- :symbol.same_as 'SYMBOL'
404
- # => still false
405
- ```
406
-
407
- Since this method is defined in Object, your own custom classes inherit it automatically, allowing you to compare literally anything at any time, without worrying about typecasting!
408
-
409
- **Make sure you define sane output for `to_s`** and you're all set.
410
-
411
- We love working with symbols in our code, but symbol values become strings when they hit the database. This meant typecasting wherever new and existing data might collide. No more!
412
-
413
- ```ruby
414
- class User
415
- attr_writer :handle
416
-
417
- def handle
418
- @handle || "faceless_one"
419
- end
420
-
421
- def to_s
422
- handle.to_s
423
- end
424
- end
425
-
426
- user = User.new
427
- :faceless_one.same_as user
428
- # => true
429
- user.same_as :faceless_one
430
- # => true
431
- user.same_as 'faceless_one'
432
- # => true
433
- user.same_as 'FACELESS_ONE'
434
- # => false
435
- ```
436
-
437
- ##### Alias
438
-
439
- `same_as` is aliased to `same_as?` for alternative clarity.
440
-
441
-
442
- #### `Object#not_nil?`
443
-
444
- Because that dangling `!` on the front of a call to `nil?` is just oh so not-ruby-chic.
445
-
446
- ```ruby
447
- nil.not_nil?
448
- # => false
449
- 'foobar'.not_nil?
450
- # => true
451
- ```
452
-
453
- Pass me one of those PBR's.
454
-
455
- #### `Object#is_an?`
456
-
457
- Alias for the [`is_a?` method](http://ruby-doc.org/core-2.2.0/Object.html#method-i-is_a-3F), for even more Ruby chic!
458
-
459
- ```ruby
460
- 1.is_a? Integer
461
- # => true, and a thorn in the side of grammar teachers everywhere!
462
- 1.is_an? Integer
463
- # => still true, but now I don't mentally pause every time I read it.
464
- ```
465
-
466
- Now pass me another PBR and my fedora.
467
-
468
- ### Extensions to `Hash`
469
-
470
- #### `Hash#delete!`
471
-
472
- The normal [`Hash#delete`](http://www.ruby-doc.org/core-2.1.5/Hash.html#method-i-delete) method returns the value that's been removed from the hash, but it can be equally useful if we return the newly modified hash instead.
473
-
474
- This approach effectively throws away the value being deleted, so don't use this when the deleted hash entry is valuable.
475
-
476
- ```ruby
477
- power_rangers = {
478
- :red => 'Jason Scott',
479
- :blue => 'Billy Cranston',
480
- :green => 'Tommy Oliver'
481
- }
482
-
483
- power_rangers.delete! :green
484
- # => { :red => 'Jason Lee Scott', :blue => 'Billy Cranston' }
485
- ```
486
-
487
- If the key is not found, the hash is returned unaltered.
488
-
489
- ```ruby
490
- power_rangers.delete! :radiant_orchid
491
- # => { :red => 'Jason Lee Scott', :blue => 'Billy Cranston' }
492
- # It probably would've triggered if I included Kimberly
493
- ```
494
-
495
- #### `Hash#delete_each`
496
-
497
- Deletes all records in a hash matching the keys passed in as an array. Returns a hash of deleted entries. Silently ignores any keys which are not found.
498
-
499
- ```ruby
500
- mega_man_bosses = { :metal_man => 1, :bubble_man => 2, :heat_man => 3, :wood_man => 4 }
501
-
502
- mega_man_bosses.delete_each :chill_penguin, :spark_mandrill
503
- # => nil, and get your series straight
504
- mega_man_bosses
505
- # => { :metal_man => 1, :bubble_man => 2, :heat_man => 3, :wood_man => 4 }
506
-
507
- mega_man_bosses.delete_each :metal_man
508
- # => { :metal_man => 1 }
509
- mega_man_bosses
510
- # => { :bubble_man => 2, :heat_man => 3, :wood_man => 4 }
511
-
512
- mega_man_bosses.delete_each :bubble_man, :heat_man, :wheel_gator
513
- # => { :bubble_man => 2, :heat_man => 3 }
514
- mega_man_bosses
515
- # => { :wood_man => 4 }
516
- ```
517
-
518
- #### `Hash#delete_each!`
519
-
520
- Same logic as `delete_each`, but return the modified hash, and discard the deleted values.
521
-
522
- Maintains parity with the contrast of `delete` vs `delete!` described above.
523
-
524
- ```ruby
525
- mega_man_bosses = { :air_man => 5, :crash_man => 6, :flash_man => 7, :quick_man => 8 }
526
-
527
- mega_man_bosses.delete_each! :yellow_devil, :air_man
528
- # => { :crash_man => 6, :flash_man => 7, :quick_man => 8 }
529
-
530
- mega_man_bosses.delete_each! :flash_man
531
- # => { :crash_man => 6, :quick_man => 8 }
532
- # Take out flash anytime after metal, I like to wait until I need a breather.
533
-
534
- mega_man_bosses.delete_each! :crash_man, :quick_man
535
- # => { }
536
- ```
537
-
538
- ### `Integer#length`
539
-
540
- Ruby doesn't provide a native way to see how many digits are in an integer, but that's exactly what we worry about anytime database `INT` lengths collide with Ruby `Fixnum` or `Bignum` values.
541
-
542
- ```ruby
543
- 1.length
544
- # => 1
545
- 9.length
546
- # => 1
547
- 90.length
548
- # => 2
549
- 900.length
550
- # => 3
551
- 9000.length
552
- # => 4
553
- 9001.length
554
- # => OVER NINE THOUSAAAAAAND (also 4)
555
-
556
- 12356469787881584554556.class.name
557
- # => "Bignum"
558
- 12356469787881584554556.length
559
- # => 23
560
- ```
561
-
562
- For consistency, we added matching methods to `Float` and `BigDecimal` that simply raise an `ArgumentError`.
563
-
564
- ```ruby
565
- 12356469.987.class.name
566
- # => "Float"
567
- 12356469.987.length
568
- # => ArgumentError: Cannot get length: "12356469.987" is not an integer
569
-
570
- 1265437718438866624512.123.class.name
571
- # => "Float" (it's really BigDecimal, trust me)
572
- 1265437718438866624512.123.length
573
- # => ArgumentError: Cannot get length: "1.2654377184388666e+21" is not an integer
574
- ```
575
-
576
- ##### Alias
577
-
578
- `length` is aliased to `digits` for alternative clarity.
579
-
580
- ### Typecasting *to* `Boolean`
581
-
582
- Boolean values are frequently represented as strings and integers in databases and file storage. So we always thought it was a little odd that Ruby lacked a boolean typecasting method, given the proliferation of `to_*` methods for `String`, `Symbol`, `Integer`, `Float`, `Hash`, etc.
583
-
584
- So we made some for `String`, `Integer`, and `Nil`.
585
-
586
- #### `String#to_bool`
587
-
588
- Strings get analyzed and return `true` or `false` for a small set of potential values.
589
-
590
- These comparisons are not case-sensitive.
591
-
592
- ```ruby
593
- ['1', 't', 'true', 'on', 'y', 'yes'].each do |true_string|
594
- true_string.to_bool
595
- # => true
596
-
597
- true_string.upcase.to_bool
598
- # => true
599
- end
600
-
601
- ['0', 'f', 'false', 'off', 'n', 'no'].each do |false_string|
602
- false_string.to_bool
603
- # => false
604
-
605
- false_string.upcase.to_bool
606
- # => false
607
- end
608
-
609
- # empty strings and strings with only spaces evaluate to false
610
- ["", " ", " ", " "].each do |empty_string|
611
- empty_string.to_bool
612
- # => false
613
- end
614
- ```
615
-
616
- A string with anything other than these matching values will throw an error.
617
-
618
- ```ruby
619
- ["foo", "tru", "trueish", "druish", "00", "000"].each do |bad_string|
620
- bad_string.to_bool
621
- # => ArgumentError: invalid value for Boolean
622
- end
623
- ```
624
-
625
- #### `Fixnum#to_bool`
626
-
627
- A zero is false, a one is true. That's it. Everything else throws `ArgumentError`.
628
-
629
- ```ruby
630
- 0.to_bool
631
- # => false
632
-
633
- 1.to_bool
634
- # => true
635
-
636
- 2.to_bool
637
- # => ArgumentError: invalid value for Boolean: "2"
638
-
639
- -1.to_bool
640
- # => ArgumentError: invalid value for Boolean: "-1"
641
-
642
- 8675309.to_bool
643
- # => ArgumentError: invalid value for Boolean: "8675309"
644
- ```
645
-
646
- #### `NilClass#to_bool`
647
-
648
- A nil value typecasted to a boolean is false.
649
-
650
- ```ruby
651
- nil == false
652
- # => false
653
-
654
- nil.to_bool
655
- # => false
656
-
657
- nil.to_bool == false
658
- # => true
659
- ```
660
-
661
- #### `TrueClass#to_bool` and `FalseClass#to_bool`
662
-
663
- In case your code calls `to_bool` on a variable of indeterminate type, they return what you expect.
664
-
665
- ```ruby
666
- true.to_bool
667
- # => true
668
-
669
- false.to_bool
670
- # => false
671
- ```
672
-
673
- ### Typecasting *from* `Boolean` and `Nil`
674
-
675
- Complementing the methods to typecast boolean values coming out of data storage, we have methods to convert booleans and `nil` into integer and symbol representations.
676
-
677
- ```ruby
678
- true.to_i
679
- # => 1
680
- true.to_sym
681
- # => :true
682
-
683
- false.to_i
684
- # => 0
685
- false.to_sym
686
- # => :false
687
-
688
- nil.to_i
689
- # => 0 (following same logic as `NilClass#to_bool`)
690
- nil.to_sym
691
- # => :nil
692
- ```
693
-
694
- ### Extensions to `Array`
695
-
696
- Ruby's [`to_h` method](http://ruby-doc.org/core-2.2.0/Array.html#method-i-to_h) converts an array to a hash by interpreting the array as an array of `[key, value]` pairs. But what if you have a one-dimensional array of things that you want to push into a hash, and the values (or keys) are yet to be determined? Finishing Moves provides a more flexible implementation.
697
-
698
- #### `Array#to_hash_values`
699
- ###### `to_hash_values(starting_key = 0, &block)`
700
-
701
- Convert an array of things into a hash with the array elements stored as values. By default the hash will be numerically indexed starting from zero.
702
-
703
- ```ruby
704
- sages = ['Rauru', 'Saria', 'Darunia', 'Princess Ruto', 'Impa', 'Nabooru', 'Zelda']
705
-
706
- sages_hash = sages.to_hash_values
707
- # => {0=>"Rauru", 1=>"Saria", 2=>"Darunia", 3=>"Princess Ruto", 4=>"Impa", 5=>"Nabooru", 6=>"Zelda"}
708
- ```
709
-
710
- `starting_key` represents where key indexing should start. Unless a block is provided, keys are assumed to be numerical and will increment by one. The above example is equivalent to `sages_hash = sages.to_hash_values(0)`.
711
-
712
- The block syntax allows you to easily increment at any rate.
713
-
714
- ```ruby
715
- sages_hash = sages.to_hash_values(0) { |key| key + 3 }
716
- # => {0=>"Rauru", 3=>"Saria", 6=>"Darunia", 9=>"Princess Ruto", 12=>"Impa", 15=>"Nabooru", 18=>"Zelda"}
717
- ```
718
-
719
- Using the block syntax you can create keys out of almost anything, making `to_hash_values` a powerful tool for generating collections of objects.
720
-
721
- ```ruby
722
- class SageElements
723
-
724
- def initialize
725
- @keys = {
726
- :first => :light,
727
- :light => :forest,
728
- :forest => :fire,
729
- :fire => :water,
730
- :water => :shadow,
731
- :shadow => :spirit,
732
- :spirit => :time,
733
- :time => :first,
734
- }
735
- end
736
-
737
- def first_key
738
- @keys[:first]
739
- end
740
-
741
- def next_key(pointer)
742
- @keys[pointer]
743
- end
744
-
745
- end
746
-
747
- sages_hash = sages.to_hash_values(elements.first_key) do |key|
748
- elements.next_key(key)
749
- end
750
- # => {:light=>"Rauru", :forest=>"Saria", :fire=>"Darunia", :water=>"Princess Ruto", :shadow=>"Impa", :spirit=>"Nabooru", :time=>"Zelda"}
751
- ```
752
-
753
- #### `Array#to_indexed_hash`
754
- ###### `to_indexed_hash(starting_key = 0)`
755
-
756
- Same logic as `to_hash_values`, but assumes an integer key, increments by 1, and skips the block syntax. It will raise an `ArgumentError` if the key is not of type `Integer` (floating point keys must use `to_hash_values` syntax).
757
-
758
- ```ruby
759
- sages.to_indexed_hash(22)
760
- # => {22=>"Rauru", 23=>"Saria", 24=>"Darunia", 25=>"Princess Ruto", 26=>"Impa", 27=>"Nabooru", 28=>"Zelda"}
761
-
762
- sages.to_indexed_hash("e")
763
- # => ArgumentError: "e" is not an integer
764
- ```
765
-
766
- ##### Alias
767
-
768
- `to_hash_values` is aliased to `to_hash_as_values` for alternative clarity.
769
-
770
- #### `Array#to_hash_keys`
771
- ###### `to_hash_keys(starting_value = 0, &block)`
772
-
773
- Convert an array of things into a hash, with the array values becoming keys. `starting_value` will be set as the value for each pair in the new array.
774
-
775
- ```ruby
776
- sages = ['Rauru', 'Saria', 'Darunia', 'Princess Ruto', 'Impa', 'Nabooru', 'Zelda']
777
-
778
- sages_hash = sages.to_hash_keys
779
- # => {"Rauru"=>0, "Saria"=>0, "Darunia"=>0, "Princess Ruto"=>0, "Impa"=>0, "Nabooru"=>0, "Zelda"=>0}
780
- ```
781
-
782
- Note that the default `starting_value` is a numerical zero rather than `nil` deliberately. Ruby reports an undefined key as `nil`, so a non-nil value ensures each hash pair is fully "existent" in Ruby terms.
783
-
784
- The block syntax allows for complex definitions of the value. This logic works precisely the same as `to_hash_values`, so see above for details.
785
-
786
- ##### Alias
787
-
788
- `to_hash_keys` is aliased to `to_hash_as_keys` for alternative clarity.
789
-
790
-
791
- #### `Array#to_hash`
792
-
793
- ###### **We Need your feedback!**
794
-
795
- This is **not** currently defined, either in the standard Ruby spec or in Finishing Moves. We planned to make it an alias of either `to_hash_values` or `to_hash_keys`, but couldn't come to an agreement about which makes more sense. If you have some input, please drop your thoughts in the issues.
796
-
797
- ### Extensions to `Enumerable`
798
-
799
- #### `Enumerable#key_map`
800
- ###### `key_map(key)`
801
-
802
- [Standard `Enumerable#map`](http://ruby-doc.org/core-2.2.0/Enumerable.html#method-i-map) has a great shortcut when you want to create an `Array` by calling a method on each element in the collection. For example:
803
-
804
- ```ruby
805
- class Pokemon
806
- attr_accessor :name
807
- def initialize(n)
808
- @name = n
809
- end
810
- end
811
-
812
- your_pokedex = [
813
- Pokemon.new("Bulbasaur"),
814
- Pokemon.new("Charmander"),
815
- Pokemon.new("Squirtle"),
816
- ]
817
- ```
818
-
819
- If you want an `Array` of Pokemon names, you use `Enumerable#map`:
820
-
821
- your_pokedex.map { |p| p.name }
822
- # => ["Bulbasaur", "Charmander", "Squirtle"]
823
-
824
- A shortcut makes it easy for trivial, repeatable method calls (such as to `:name`):
825
-
826
- your_pokedex.map(&:name)
827
- # => ["Bulbasaur", "Charmander", "Squirtle"]
828
-
829
- But what happens when my Pokedex isn't as well-structured as yours?
830
-
831
- ```ruby
832
- my_pokedex = [
833
- {name: "Bulbasaur"},
834
- {name: "Charmander"},
835
- {name: "Squirtle"},
836
- ]
837
- ```
838
-
839
- I can still map the `:name` keys out to an `Array` with full block notation...
840
-
841
- my_pokedex.map { |p| p[:name] }
842
- # => ["Bulbasaur", "Charmander", "Squirtle"]
843
-
844
- But such sad! I can haz no shortcut.
845
-
846
- my_pokedex.map(??????)
847
- # => ["Bulbasaur", "Charmander", "Squirtle"]
848
-
849
- Enter `Enumerable#key_map`:
850
-
851
- my_pokedex.key_map(:name)
852
- # => ["Bulbasaur", "Charmander", "Squirtle"]
853
-
854
- #### `Enumerable#key_map_reduce`
855
- ###### `key_map_reduce(key, arg = :+, &block)`
856
-
857
- Building off of `Enumerable#key_map`, finishing_moves provides a convenience method when you need to perform a one-step map/reduce operation on a collection.
858
-
859
- ```ruby
860
- my_pokedex = [
861
- {name: "Bulbasaur", level: 2},
862
- {name: "Charmander", level: 2},
863
- {name: "Squirtle", level: 2},
864
- ]
865
- ```
866
-
867
- In other words, this map/reduce operation
868
-
869
- my_pokedex.key_map(:level).reduce(0) { |memo,lvl| memo + lvl }
870
- # => 6
871
-
872
- can be simplified to
873
-
874
- my_pokedex.key_map_reduce(:level, :+)
875
- # => 6
876
-
877
- where `:+` can be any named method of `memo`, and is applied to each value (just as in [`Enumerable#reduce`](http://ruby-doc.org/core-2.2.0/Enumerable.html#method-i-reduce)). For additional flexibility, you can pass an intial value for `memo` and a custom `block` (and again, this works just like `Enumerable#reduce`):
878
-
879
- my_pokedex.key_map_reduce(:level, 0) { |memo,lvl| memo + lvl }
880
- # => 6
881
-
882
- ### Extensions to `String`
883
-
884
- #### `String#dedupe`
885
- ###### `dedupe(str)`
886
-
887
- Find multiple concurrent occurrences of a character and reduce them to a single occurrence.
888
-
889
- ```ruby
890
- 'hello___world'.dedupe('_')
891
- # => 'hello_world'
892
-
893
- '/crazy//concatenated////file/path'.dedupe('/')
894
- # => '/crazy/concatenated/file/path'
895
- ```
896
-
897
- You can dedupe multiple characters by passing them all together within a single string.
898
-
899
- ```ruby
900
- 'foo___bar_baz---bing'.dedupe('-_')
901
- # => 'foo_bar_baz-bing'
902
- ```
903
-
904
- `dedupe` won't automatically strip leading or trailing characters. You'll want to combine it with [`strip_all`](#stringstrip_all) to do that.
905
-
906
- ```ruby
907
- '/crazy//concatenated////file/path/'.dedupe('/')
908
- # => '/crazy/concatenated/file/path/'
909
-
910
- '/crazy//concatenated////file/path/'.dedupe('/').strip_all('/')
911
- # => 'crazy/concatenated/file/path'
912
- ```
913
-
914
- ##### Bang variant
915
-
916
- `dedupe!` will perform the modifications in place, rather than returning a copy.
917
-
918
- #### `String#keyify`
919
-
920
- Sometimes we find ourselves in need of a codified version of a string value. For example, user-generated values that must be compared for basic sameness, or creating database keys based on user-driven data entry. We use `keyify` in these situations to normalize the string down into a handy code for these comparison and data storage purposes.
22
+ ### Ruby Version
921
23
 
922
- `keyify` will perform the following actions...
24
+ Tested against **`2.0.0` and above**. Probably works in `1.9.3`.
923
25
 
924
- 1. Replace all non-alphanumerics with underscores
925
- 2. Convert any existing `CamelCase` into `snake_case`
926
- 3. Strip any leading numbers and underscores
927
- 4. Combine multiple concurrent underscores into a single one
928
- 5. Convert to lowercase
929
- 6. Return as a symbol
930
-
931
- ```ruby
932
- 'FooBarBaz'.keyify
933
- # => :foo_bar_baz
934
-
935
- "Foo-Bar'Baz".keyify
936
- # => :foo_bar_baz
937
-
938
- '1234FooBAR'.keyify
939
- # => :foo_bar
940
-
941
- # Works with symbols as well
942
- :FooBarBaz.keyify
943
- # => :foo_bar_baz
944
- ```
945
-
946
- Say a person's name is entered into a system by two different people, and we must now compare the values to see if they match. We all know user-entered data sucks, hopefully `keyify` can make it suck just a little less.
947
-
948
- ```ruby
949
- 'John Doe'.keyify
950
- # => :john_doe
951
-
952
- 'JOHN DOE'.keyify
953
- # => :john_doe
954
-
955
- 'John Doe'.keyify == 'JOHN DOE'.keyify
956
- # => true
957
-
958
- "Ted O'Baxter".keyify == 'Ted O Baxter'.keyify
959
- # => true
960
- ```
961
-
962
- How about a dropdown menu populated with options created by end users? An identifier other than the database's primary key can often be useful.
963
-
964
- ```ruby
965
- 'Not a covered benefit'.keyify
966
- # => :not_a_covered_benefit
967
-
968
- "User's Duplicate Claim".keyify
969
- # => :user_s_duplicate_claim
970
-
971
- "Included in global amount/bundled".keyify
972
- # => :included_in_global_amount_bundled
973
- ```
974
-
975
- In case you need something from the Ruby-verse, `keyify` also works on static class declarations.
976
-
977
- ```ruby
978
- Integer.keyify
979
- # => :integer
980
-
981
- Math::DomainError.keyify
982
- # => :math_domain_error
983
- ```
984
-
985
- It also makes it easy to build a hash with keys based on string values.
986
-
987
- ```ruby
988
- my_hash = {}
989
- ['Option A', 'Option B', 'Option C', 'Option D'].each do |opt|
990
- my_hash[opt.keyify] = opt
991
- end
992
-
993
- my_hash
994
- # => {:option_a=>"Option A", :option_b=>"Option B", :option_c=>"Option C", :option_d=>"Option D"}
995
- ```
996
-
997
- ##### Bang variant
998
-
999
- The `keyify!` version performs the same actions, but will raise an `ArgumentError` if the value being keyified results in an empty string.
1000
-
1001
- ```ruby
1002
- ' '.keyify!
1003
- # => ArgumentError: " " cannot be keyified, no valid characters
1004
-
1005
- '!@#$%^'.keyify!
1006
- # => ArgumentError: "!@#$%^" cannot be keyified, no valid characters
1007
-
1008
- '12345678'.keyify!
1009
- # => ArgumentError: "12345678" cannot be keyified, no valid characters
1010
- ```
1011
-
1012
- #### `String#match?`
1013
-
1014
- Ruby's [`match` method](http://ruby-doc.org/core-2.2.0/String.html#method-i-match) is often used in boolean operations to determine the presence or absence of a given pattern within a string. That's why we found it odd that Ruby doesn't include a shortcut method to return a boolean result.
1015
-
1016
- `match?` operates exactly like `match`, and simply returns `true` or `false` based on the results of the lookup.
1017
-
1018
- ```ruby
1019
- 'hello'.match?('he')
1020
- # => true
1021
-
1022
- 'hello'.match?('o')
1023
- # => true
1024
-
1025
- 'hello'.match?('(.)')
1026
- # => true
1027
-
1028
- 'hello'.match?(/(.)/)
1029
- # => true
1030
-
1031
- 'hello'.match?('xx')
1032
- # => false
1033
-
1034
- 'hello'.match?('he', 1)
1035
- # => false
1036
- ```
1037
-
1038
- #### `String#nl2br`
1039
-
1040
- Converts newlines in a string into break tags. Will recognize Unix line feed (`\n`), standalone carriage returns (`\r`), and Windows formats (both `\r\n` and the improperly formatted `\n\r`).
1041
-
1042
- A Unix newline is appended immediately following each break tag replacement.
1043
-
1044
- ```ruby
1045
- "\n".nl2br
1046
- # => "<br />\n"
1047
-
1048
- "\n\r".nl2br
1049
- # => "<br />\n"
1050
-
1051
- "\r\n".nl2br
1052
- # => "<br />\n"
1053
-
1054
- "\n\r\n".nl2br
1055
- # => "<br />\n<br />\n"
1056
-
1057
- "\r\n\r\n".nl2br
1058
- # => "<br />\n<br />\n"
1059
-
1060
- "\r\r\n".nl2br
1061
- # => "<br />\n<br />\n"
1062
-
1063
- "\r\r".nl2br
1064
- # => "<br />\n<br />\n"
1065
-
1066
- "\n\r\r".nl2br
1067
- # => "<br />\n<br />\n"
1068
- ```
1069
-
1070
- #### `String#remove_whitespace`
1071
-
1072
- Removes all the whitespace from a string. No muss, no fuss.
1073
-
1074
- ```ruby
1075
- ' a b c d e'.remove_whitespace
1076
- # => 'abcde'
1077
-
1078
- # Absolutely any string is valid
1079
- '. $ ^ { [ ( " | " ) * + ?'.remove_whitespace
1080
- # => '.$^{[("|")*+?'
1081
- ```
1082
-
1083
- You can optionally provide a string that will replace the whitespace, rather than remove it entirely.
1084
-
1085
- ```ruby
1086
- '1 2 3 4 5'.remove_whitespace('+')
1087
- # => '1+2+3+4+5'
1088
- ```
1089
-
1090
- Be careful, as `remove_whitespace` won't consolidate spaces before performing a replacement! If that's necessary, you should run your string over the [`dedupe`](#stringdedupe) method first.
1091
-
1092
- ```ruby
1093
- '1 2 3 4 5'.remove_whitespace('+')
1094
- # => '1+++2+3+4+5'
1095
-
1096
- '1 2 3 4 5'.dedupe(' ').remove_whitespace('+')
1097
- # => '1+2+3+4+5'
1098
- ```
1099
-
1100
- #### `String#strip_all`
1101
-
1102
- Ruby's [`strip` method](http://ruby-doc.org/core-2.2.0/String.html#method-i-strip) removes leading and trailing whitespace, but there's no method to strip other characters like dashes, underscores, or numbers. `strip_all` allows you to perform these kinds of cleanups without having to write any regular expressions.
1103
-
1104
- The lone argument is a string of the characters you want to remove. By default, `strip_all` will remove dashes `-` and underscores `_`.
1105
-
1106
- ```ruby
1107
- '___foo___'.strip_all
1108
- # => 'foo'
1109
-
1110
- '---foo---'.strip_all
1111
- # => 'foo'
1112
- ```
1113
-
1114
- Note that the argument is processed as a **regex group** (your argument ends up inside of a regex `[]`). This means we evaluate the individual characters of the argument, not an explicit character sequence. You do not need spaces between the characters.
1115
-
1116
- ```ruby
1117
- '__-_--foo--_-__'.strip_all
1118
- # => 'foo'
1119
-
1120
- '123foo123'.strip_all('321')
1121
- # => 'foo'
1122
-
1123
- 'xXxXfooXxXx'.strip_all('XYZx')
1124
- # => 'foo'
1125
- ```
1126
-
1127
- Case-sensitivity still applies.
1128
-
1129
- ```ruby
1130
- 'ABCfooABC'.strip_all('abc')
1131
- # => 'ABCfooABC'
1132
- ```
1133
-
1134
- `strip_all` is intended to be a drop-in enhancement of `strip`, and will therefore always remove whitespace and newlines, even when providing your own set of characters.
1135
-
1136
- ```ruby
1137
- "//// foo ////\n".strip_all('/')
1138
- # => 'foo'
1139
- ```
1140
-
1141
- Everything passed in is escaped by default, so you don't have to worry about symbols.
1142
-
1143
- ```ruby
1144
- '/[a|valid|regex]+/'.strip_all('/[]+|')
1145
- # => 'a|valid|regex'
1146
-
1147
- # The | pipes are still present because they are not leading or trailing in this string.
1148
- # Remember, we're enhancing the strip method.
1149
- ```
1150
-
1151
- The one exception is when you pass in regex character ranges: `0-9`, `a-z`, and `A-Z`. Those will be read as expressions to capture all numbers, all lowercase or all uppercase letters, respectively.
1152
-
1153
- ```ruby
1154
- '0123456789 foo 9876543210'.strip_all('0-9')
1155
- # => 'foo'
1156
-
1157
- 'FOO 314 BARBAZ'.strip_all('A-Z')
1158
- # => '314'
1159
-
1160
- 'hello--314--world'.strip_all('a-z')
1161
- # => '--314--'
1162
-
1163
- 'hello--314--world'.strip_all('a-z-') # note the extra dash at the end
1164
- # => '314'
1165
-
1166
- # you can really shoot yourself in the foot if you're not careful
1167
- 'hello world'.strip_all('a-z')
1168
- # => ''
1169
-
1170
- 'abcdefghijklm foo123 nopqrstuvwxyz'.strip_all('a-z0-9')
1171
- # => ''
1172
- ```
1173
-
1174
- ##### Variants
26
+ ## List of Methods
27
+ ##### (all documented in the [GitHub wiki](https://github.com/forgecrafted/finishing_moves/wiki))
28
+
29
+ - [`Array#to_hash_values`](https://github.com/forgecrafted/finishing_moves/wiki/Array#arrayto_hash_values)
30
+ - [`Array#to_indexed_hash`](https://github.com/forgecrafted/finishing_moves/wiki/Array#arrayto_indexed_hash)
31
+ - [`Array#to_hash_keys`](https://github.com/forgecrafted/finishing_moves/wiki/Array#arrayto_hash_keys)
32
+ - [`Enumerable#key_map`](https://github.com/forgecrafted/finishing_moves/wiki/Enumerable#enumerablekey_map)
33
+ - [`Enumerable#key_map_reduce`](https://github.com/forgecrafted/finishing_moves/wiki/Enumerable#enumerablekey_map_reduce)
34
+ - [`Hash#delete!`](https://github.com/forgecrafted/finishing_moves/wiki/Hash#hashdelete)
35
+ - [`Hash#delete_each`](https://github.com/forgecrafted/finishing_moves/wiki/Hash#hashdelete_each)
36
+ - [`Hash#delete_each!`](https://github.com/forgecrafted/finishing_moves/wiki/Hash#hashdelete_each-1)
37
+ - [`Integer#length`](https://github.com/forgecrafted/finishing_moves/wiki/Integer#integerlength)
38
+ - [`Kernel#nil_chain`](https://github.com/forgecrafted/finishing_moves/wiki/Kernel#kernelnil_chain)
39
+ - [`Kernel#cascade`](https://github.com/forgecrafted/finishing_moves/wiki/Kernel#kernelcascade)
40
+ - [`Kernel#class_exists?`](https://github.com/forgecrafted/finishing_moves/wiki/Kernel#kernelclass_exists)
41
+ - [`Object#same_as`](https://github.com/forgecrafted/finishing_moves/wiki/Object#objectsame_as)
42
+ - [`Object#not_nil?`](https://github.com/forgecrafted/finishing_moves/wiki/Object#objectnot_nil)
43
+ - [`Object#is_an?`](https://github.com/forgecrafted/finishing_moves/wiki/Object#objectis_an)
44
+ - [`String#dedupe`](https://github.com/forgecrafted/finishing_moves/wiki/String#stringdedupe)
45
+ - [`String#keyify`](https://github.com/forgecrafted/finishing_moves/wiki/String#stringkeyify)
46
+ - [`String#match?`](https://github.com/forgecrafted/finishing_moves/wiki/String#stringmatch)
47
+ - [`String#nl2br`](https://github.com/forgecrafted/finishing_moves/wiki/String#stringnl2br)
48
+ - [`String#remove_whitespace`](https://github.com/forgecrafted/finishing_moves/wiki/String#stringremove_whitespace)
49
+ - [`String#strip_all`](https://github.com/forgecrafted/finishing_moves/wiki/String#stringstrip_all)
50
+ - [Boolean Typecasting](https://github.com/forgecrafted/finishing_moves/wiki/Boolean-Typecasting)
1175
51
 
1176
- We provide the same set of associated methods as `strip`.
52
+ ## Development approach
1177
53
 
1178
- - **`lstrip_all`** removes only leading characters
1179
- - **`rstrip_all`** removes only trailing characters
1180
- - All three have bang variants -- **`strip_all!`**, **`lstrip_all!`**, and **`rstrip_all!`** -- that perform the replacement in place, rather than returning a copy.
54
+ - **Never** override default Ruby behavior, only add functionality.
55
+ - Follow the Unix philosophy of *"Do one job really well."*
56
+ - Minimize assumptions, e.g. avoid formatting output, mutating values, and conditional logic flows.
57
+ - Play nice with major Ruby players like Rake, Rails, and Sinatra.
58
+ - Never duplicate existing methods from Rails and the like.
59
+ - Test all the things.
1181
60
 
1182
61
  ## Bug Reports
1183
62
 
1184
63
  [Drop us a line in the issues section](https://github.com/forgecrafted/finishing_moves/issues).
1185
64
 
1186
- **Be sure to include some sample code that reproduces the problem.**
65
+ **Be sure to include sample code that reproduces the problem.**
1187
66
 
1188
67
  ## Add your own finisher!
1189
68
 
@@ -1193,9 +72,6 @@ We provide the same set of associated methods as `strip`.
1193
72
  4. Repeat steps 2 and 3 until you see a brilliant luster
1194
73
  5. Submit a pull request
1195
74
 
1196
- ###### Got a good nerdy reference for our code samples?
1197
- We'll take pull requests on those too. Bonus karma points if you apply the reference to the specs too.
1198
-
1199
75
  ## Credits
1200
76
 
1201
77
  [![forge software](http://www.forgecrafted.com/logo.png)](http://www.forgecrafted.com)