rearmed 1.3.1 → 2.0.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
- SHA1:
3
- metadata.gz: 8cd8b9873096a342bb640e7bab688970350bf050
4
- data.tar.gz: 84ac122091acba8d89b1c4f1b99bf2e9ff3896e2
2
+ SHA256:
3
+ metadata.gz: 5e9c5aa5c6b89f77aeae8704f39ad697f5fa90fcf2defb344b01e1a74374fe53
4
+ data.tar.gz: 50ab78b692722a964136b0e7ddfc6a2f4d0cf27f574fdc097e760d64ade52622
5
5
  SHA512:
6
- metadata.gz: 704335a6f2403d194b54bfbca86c6660d49f3c6a5eab6eb2031d813032e9c7d62ea7b03f35d11dd6a11adf251a6b15c706e39046e2fb298f093d2904e313ddd7
7
- data.tar.gz: d8d2552250bacd242eac8e83d492d6cde941a0177d4cbbc8888fececb7ffe568b7f336fa553bcc18746214dc02836744f3542aa34c998ba4694f8ea820e170fd
6
+ metadata.gz: 5faf458204002b2096d67c5eb0bdf79852cfe86a014ade04b6546a43516e45b441c1cd6dbc45738d4a196507c988841c9af2eca57bcdd6f08b67f401d44ce0a1
7
+ data.tar.gz: 3e825f05d3ff172f366845faa5eb44347c4f9b8110834cb915bb2bbd766db266618930f27446b3a2a803ca5b8e1b16ec728adc702911da85137eb935c5e267c1
@@ -1,6 +1,15 @@
1
1
  CHANGELOG
2
2
  ---------
3
3
 
4
+ - **2.0.0 - July 11, 2018**
5
+ - Rename all generic `Rearmed` methods to their respective object type subclass and add type checking. Three examples:
6
+ - `Rearmed.casecmp?(str1, str2)` changed to `Rearmed::String.casecmp?(str1, str2)`
7
+ - `Rearmed.hash_join(h)` changed to `Rearmed::Hash.join?(h)`
8
+ - `Rearmed.dig` is the only exception will remained at the global `Rearmed` namespace. This method is shared by both Array and Hash and also is used internally throughout the library.
9
+ - Change method of applying patches from `require 'rearmed/apply_patches'` to `Rearmed#apply_patches!`. Once `apply_patches!` has been called, then `enabled_patches` cannot be changed. If it is, it will raise a `PatchesAlreadyAppliedError`
10
+ - Overhaul `Rearmed#enabled_patches=` method with type checking
11
+ - Allow setting `:all` for `Rearmed#enabled_patches=`
12
+ - Add `Integer#length`, `Object#bool?`, `Object#true?`, `Object#false?`, `String#match?`. These methods were all borrowed from [`finishing_moves`](https://github.com/forgecrafted/finishing_moves), Thanks!
4
13
  - **1.3.1 - Sept 2, 2017**
5
14
  - Add `Enumerable#select_map`
6
15
  - Add `String#casecmp?` for Ruby 2.3.x and below
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
- # Rearmed Ruby <a href='https://travis-ci.org/westonganger/rearmed-rb' target='_blank'><img src='https://api.travis-ci.org/westonganger/rearmed-rb.svg?branch=master' border='0' alt='Build Status' /></a>
1
+ # Rearmed Ruby
2
2
 
3
- <a href='https://ko-fi.com/A5071NK' target='_blank'><img height='32' style='border:0px;height:32px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=a' border='0' alt='Buy Me a Coffee' /></a>
3
+ <a href="https://badge.fury.io/rb/rearmed" target="_blank"><img height="21" style='border:0px;height:21px;' border='0' src="https://badge.fury.io/rb/rearmed.svg" alt="Gem Version"></a>
4
+ <a href='https://travis-ci.org/westonganger/rearmed-rb' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://api.travis-ci.org/westonganger/rearmed-rb.svg?branch=master' border='0' alt='Build Status' /></a>
5
+ <a href='https://rubygems.org/gems/rearmed' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://ruby-gem-downloads-badge.herokuapp.com/rearmed?label=rubygems&type=total&total_label=downloads&color=brightgreen' border='0' alt='RubyGems Downloads' /></a>
6
+ <a href='https://ko-fi.com/A5071NK' target='_blank'><img height='22' style='border:0px;height:22px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=a' border='0' alt='Buy Me a Coffee' /></a>
4
7
 
5
8
  A collection of helpful methods and monkey patches for Arrays, Hash, Enumerables, Strings, Objects & Dates in Ruby. [Rearmed is a collection of plugins](https://github.com/westonganger?utf8=%E2%9C%93&tab=repositories&q=rearmed) which are driven by making life easier & coding more natural.
6
9
 
@@ -18,15 +21,15 @@ gem 'rearmed'
18
21
 
19
22
  # Usage
20
23
 
21
- ## Setup Enabled Monkey Patches (all are optional)
24
+ ## Setup Monkey Patches (all are opt-in)
22
25
 
23
26
  ```ruby
24
27
  # config/initializers/rearmed.rb
25
28
 
26
29
  Rearmed.enabled_patches = {
27
30
  array: {
28
- dig: false,
29
31
  delete_first: false,
32
+ dig: false,
30
33
  not_empty: false
31
34
  },
32
35
  date: {
@@ -44,14 +47,21 @@ Rearmed.enabled_patches = {
44
47
  only: false,
45
48
  to_struct: false
46
49
  },
50
+ integer: {
51
+ length: false
52
+ },
47
53
  object: {
54
+ bool?: false,
55
+ false?: false,
48
56
  in: false,
49
- not_nil: false
57
+ not_nil: false,
58
+ true?: false
50
59
  },
51
60
  string: {
52
61
  begins_with: false,
53
- casecmp?: false
62
+ casecmp?: false,
54
63
  ends_with: false,
64
+ match?: false,
55
65
  starts_with: false,
56
66
  to_bool: false,
57
67
  valid_float: false,
@@ -59,10 +69,34 @@ Rearmed.enabled_patches = {
59
69
  }
60
70
  }
61
71
 
72
+ Rearmed.apply_patches!
73
+ ```
74
+
75
+ Some other argument formats the `enabled_patches` option accepts are:
62
76
 
63
- require 'rearmed/apply_patches'
77
+ ```ruby
78
+ ### Enable everything
79
+ Rearmed.enabled_patches = :all
80
+
81
+ ### Disable everything
82
+ Rearmed.enabled_patches = nil
83
+
84
+ ### Hash values can be boolean/nil values also
85
+ Rearmed.enabled_patches = {
86
+ array: true,
87
+ date: {
88
+ now: true
89
+ },
90
+ enumerable: true,
91
+ hash: false,
92
+ integer: false,
93
+ object: nil,
94
+ string: nil
95
+ }
64
96
  ```
65
97
 
98
+ By design, once `Rearmed.apply_patches!` is called then `Rearmed.enabled_patches` is no longer editable and `Rearmed.apply_patches!` cannot be called again. If you try to do so, it will raise a `PatchesAlreadyAppliedError`. There is no-built in way of changing the patches, if you need to do so (which you shouldn't) that is up to you to figure out.
99
+
66
100
  ## Array Methods
67
101
  ```ruby
68
102
  array = [1,2,1,4,1]
@@ -133,6 +167,10 @@ my_var.not_nil?
133
167
  # Only monkey patched if not using ActiveSupport / Rails as this method is already defined there
134
168
  my_var.in?([1,2,3])
135
169
  my_var.in?(1,2,3) # or with splat arguments
170
+
171
+ my_var.bool? # if is true or false boolean value
172
+ my_var.true? # if is true boolean value
173
+ my_var.false? # if is false boolean value
136
174
  ```
137
175
 
138
176
  ## String
@@ -143,9 +181,14 @@ my_var.in?(1,2,3) # or with splat arguments
143
181
  '123.123'.valid_float?
144
182
  # or without monkey patch: Rearmed.valid_float?('123.123')
145
183
 
184
+ '123.123'.valid_number?
185
+ # or without monkey patch: Rearmed.valid_number?('123.123')
186
+
146
187
  'true'.to_bool
147
188
  # or without monkey patch: Rearmed.to_bool('true')
148
189
 
190
+ 'foo'.match?(/fo/) #=> true, this method returns a convenient boolean value instead of matchdata
191
+
149
192
  # alias of start_with? and end_with? to have more sensible method names
150
193
  'foo'.starts_with?('fo') # => true
151
194
  'foo'.begins_with?('fo') # => true
@@ -158,19 +201,19 @@ my_var.in?(1,2,3) # or with splat arguments
158
201
  ```
159
202
 
160
203
  # Contributing / Todo
161
- If you want to request a method please raise an issue and we can discuss the implementation.
162
-
163
- If you want to contribute here are a couple of things you could do:
204
+ If your looking to contribute here is a list of outstanding items:
164
205
 
165
206
  - Get the `natural_sort` method to accept a block
166
207
 
208
+ To request or add a method, please raise an issue and we can discuss the implementation.
209
+
167
210
 
168
211
  # Credits
169
212
  Created by Weston Ganger - [@westonganger](https://github.com/westonganger)
170
213
 
171
214
  For any consulting or contract work please contact me via my company website: [Solid Foundation Web Development](https://solidfoundationwebdev.com)
172
215
 
173
- ## Similar Libraries Created By Me
216
+ ## Other Libraries in the Rearmed family of Plugins
174
217
  - [Rearmed Rails](https://github.com/westonganger/rearmed_rails)
175
218
  - [Rearmed-JS](https://github.com/westonganger/rearmed-js)
176
219
  - [Rearmed-CSS](https://github.com/westonganger/rearmed-css)
data/Rakefile CHANGED
@@ -3,28 +3,19 @@ require 'bundler/gem_tasks'
3
3
 
4
4
  task :test do
5
5
  require 'rake/testtask'
6
+
6
7
  Rake::TestTask.new do |t|
7
8
  t.libs << 'test'
8
- t.test_files = FileList['test/**/tc_*.rb']
9
+ t.test_files = FileList['test/**/*_test.rb']
9
10
  t.verbose = true
10
11
  end
11
12
  end
12
13
 
13
14
  task :console do
14
15
  require 'rearmed'
15
- Rearmed.enabled_patches = {
16
- array: true,
17
- hash: true,
18
- object: true,
19
- string: true,
20
- date: true,
21
- enumerable: true,
22
- rails_3: true,
23
- rails_4: true,
24
- rails: true,
25
- minitest: true
26
- }
27
- require 'rearmed/apply_patches'
16
+
17
+ Rearmed.enabled_patches = :all
18
+ Rearmed.apply_patches!
28
19
 
29
20
  require 'irb'
30
21
  binding.irb
@@ -5,14 +5,63 @@ require 'rearmed/exceptions'
5
5
 
6
6
  module Rearmed
7
7
 
8
- @enabled_patches = eval(File.read(File.join(File.dirname(__FILE__), 'rearmed/default_enabled_patches.hash')))
8
+ DEFAULT_PATCHES = {
9
+ array: {},
10
+ date: {},
11
+ enumerable: {},
12
+ hash: {},
13
+ integer: {},
14
+ object: {},
15
+ string: {},
16
+ }.freeze
17
+ private_constant :DEFAULT_PATCHES
18
+
19
+ @enabled_patches = Marshal.load(Marshal.dump(DEFAULT_PATCHES))
20
+ @applied = false
9
21
 
10
22
  def self.enabled_patches=(val)
11
- @enabled_patches = val
23
+ if @applied
24
+ raise ::Rearmed::Exceptions::PatchesAlreadyAppliedError.new
25
+ else
26
+ if [nil, {}].include?(val)
27
+ @enabled_patches = Marshal.load(Marshal.dump(DEFAULT_PATCHES))
28
+ elsif val == :all
29
+ @enabled_patches = val
30
+ elsif val.is_a?(::Hash)
31
+ @enabled_patches = {}
32
+
33
+ DEFAULT_PATCHES.keys.each do |k|
34
+ methods = val[k] || val[k.to_sym]
35
+ if methods
36
+ if methods.is_a?(::Hash) || methods == true
37
+ @enabled_patches[k] = methods
38
+ else
39
+ raise TypeError.new('Invalid value within the hash passed to Rearmed.enabled_patches=')
40
+ end
41
+ else
42
+ @enabled_patches[k] = {}
43
+ end
44
+ end
45
+ else
46
+ raise TypeError.new('Invalid value passed to Rearmed.enabled_patches=')
47
+ end
48
+ end
12
49
  end
13
50
 
14
51
  def self.enabled_patches
15
52
  @enabled_patches
16
53
  end
17
54
 
55
+ def self.apply_patches!
56
+ if @applied
57
+ raise ::Rearmed::Exceptions::PatchesAlreadyAppliedError.new
58
+ else
59
+ Dir[File.join(__dir__, 'rearmed/monkey_patches/*.rb')].each do |filename|
60
+ require filename
61
+ end
62
+
63
+ @applied = true
64
+ end
65
+ end
66
+
18
67
  end
@@ -2,22 +2,28 @@ module Rearmed
2
2
  module Exceptions
3
3
 
4
4
  class BlockFoundError < StandardError
5
- def initialize(klass=nil)
5
+ def initialize
6
6
  super("Rearmed doesn't yet support a block on this method.")
7
7
  end
8
8
  end
9
9
 
10
10
  class NoArgOrBlockGivenError < StandardError
11
- def initialize(klass=nil)
11
+ def initialize
12
12
  super("Must pass an argument or a block.")
13
13
  end
14
14
  end
15
15
 
16
16
  class BothArgAndBlockError < StandardError
17
- def initialize(klass=nil)
17
+ def initialize
18
18
  super("Arguments and blocks must be used seperately.")
19
19
  end
20
20
  end
21
21
 
22
+ class PatchesAlreadyAppliedError < StandardError
23
+ def initialize
24
+ super("Cannot change or apply patches again after `Rearmed#apply_patches!` has been called.")
25
+ end
26
+ end
27
+
22
28
  end
23
29
  end
@@ -1,129 +1,181 @@
1
1
  module Rearmed
2
2
 
3
- def self.casecmp?(str1, str2)
4
- if str1.is_a?(String) && str2.is_a?(String)
5
- str1.casecmp(str2) == 0
6
- end
7
- end
8
-
9
3
  def self.dig(collection, *values)
10
- current_val = nil
11
- current_collection = collection
12
- values.each_with_index do |val,i|
13
- if i+1 == values.length
14
- if (current_collection.is_a?(Array) && val.is_a?(Integer)) || (current_collection.is_a?(Hash) && ['String','Symbol'].include?(val.class.name))
15
- current_val = current_collection[val]
16
- else
17
- current_val = nil
18
- end
19
- elsif current_collection.is_a?(Array)
20
- if val.is_a?(Integer)
21
- current_collection = current_collection[val]
22
- next
4
+ if collection.is_a?(::Hash) || collection.is_a?(::Array)
5
+ current_val = nil
6
+ current_collection = collection
7
+ values.each_with_index do |val,i|
8
+ if i+1 == values.length
9
+ if (current_collection.is_a?(::Array) && val.is_a?(::Integer)) || (current_collection.is_a?(::Hash) && [::String, ::Symbol].include?(val.class))
10
+ current_val = current_collection[val]
11
+ else
12
+ current_val = nil
13
+ end
14
+ elsif current_collection.is_a?(::Array)
15
+ if val.is_a?(::Integer)
16
+ current_collection = current_collection[val]
17
+ next
18
+ else
19
+ current_val = nil
20
+ break
21
+ end
22
+ elsif current_collection.is_a?(::Hash)
23
+ if [::String, ::Symbol].include?(val.class)
24
+ current_collection = current_collection[val]
25
+ next
26
+ else
27
+ current_val = nil
28
+ break
29
+ end
23
30
  else
24
31
  current_val = nil
25
- break
26
- end
27
- elsif current_collection.is_a?(Hash)
28
- if ['Symbol','String'].include?(val.class.name)
29
- current_collection = current_collection[val]
30
- next
31
- else
32
- current_val = nil
33
- break
32
+ break
34
33
  end
34
+ end
35
+
36
+ return current_val
37
+ else
38
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a Hash or Array")
39
+ end
40
+ end
41
+
42
+ module Hash
43
+ def self.compact(hash)
44
+ if hash.is_a?(::Hash)
45
+ hash.reject{|_, value| value.nil?}
35
46
  else
36
- current_val = nil
37
- break
47
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a Hash")
38
48
  end
39
49
  end
40
50
 
41
- return current_val
42
- end
51
+ def self.join(hash, delimiter=', ', &block)
52
+ if hash.is_a?(::Hash)
53
+ unless block_given?
54
+ block = ->(k,v){ "#{k}: #{v}" }
55
+ end
43
56
 
44
- def self.hash_compact(hash)
45
- hash.reject{|_, value| value.nil?}
46
- end
57
+ str = ""
47
58
 
48
- def self.hash_join(hash, delimiter=', ', &block)
49
- unless block_given?
50
- block = ->(k,v){ "#{k}: #{v}" }
51
- end
59
+ hash.each_with_index do |(k,v), i|
60
+ val = block.call(k,v)
61
+ unless val.is_a?(::String)
62
+ val = val.to_s
63
+ end
64
+ str << val
52
65
 
53
- str = ""
66
+ if i+1 < hash.length
67
+ str << delimiter
68
+ end
69
+ end
54
70
 
55
- hash.each_with_index do |(k,v), i|
56
- val = block.call(k,v)
57
- unless val.is_a?(String)
58
- val = val.to_s
71
+ return str
72
+ else
73
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a Hash")
59
74
  end
60
- str << val
75
+ end
61
76
 
62
- if i+1 < hash.length
63
- str << delimiter
77
+ def self.only(hash, *keys)
78
+ if hash.is_a?(::Hash)
79
+ keys.map!{|key| hash.convert_key(key)} if hash.respond_to?(:convert_key, true)
80
+ keys.each_with_object(hash.class.new){|k, new_hash| new_hash[k] = hash[k] if hash.has_key?(k)}
81
+ else
82
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a Hash")
64
83
  end
65
84
  end
66
85
 
67
- return str
68
- end
69
-
70
- def self.hash_only(hash, *keys)
71
- keys.map!{|key| hash.convert_key(key)} if hash.respond_to?(:convert_key, true)
72
- keys.each_with_object(hash.class.new){|k, new_hash| new_hash[k] = hash[k] if hash.has_key?(k)}
86
+ def self.to_struct(hash)
87
+ if hash.is_a?(::Hash)
88
+ Struct.new(*hash.keys).new(*hash.values)
89
+ else
90
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a Hash")
91
+ end
92
+ end
73
93
  end
74
94
 
75
- def self.hash_to_struct(hash)
76
- Struct.new(*hash.keys).new(*hash.values)
77
- end
95
+ module Enumerable
96
+ def self.natural_sort_by(collection)
97
+ if collection.is_a?(::Enumerable)
98
+ collection.sort_by{|x| self._naturalize_str(yield(x))}
99
+ else
100
+ raise TypeError.new("Invalid object passed to #{__method__}, must be an Enumerable")
101
+ end
102
+ end
78
103
 
79
- def self.natural_sort_by(collection)
80
- collection.sort_by{|x| self.naturalize_str(yield(x))}
81
- end
104
+ def self.natural_sort(collection, options={})
105
+ if !collection.is_a?(::Enumerable)
106
+ raise TypeError.new("Invalid object passed to #{__method__}, must be an Enumerable")
107
+ elsif block_given?
108
+ Rearmed::Exceptions::BlockFoundError
109
+ else
110
+ collection.sort do |a,b|
111
+ if options[:reverse] == true
112
+ self._naturalize_str(b.to_s) <=> self._naturalize_str(a.to_s)
113
+ else
114
+ self._naturalize_str(a.to_s) <=> self._naturalize_str(b.to_s)
115
+ end
116
+ end
117
+ end
118
+ end
82
119
 
83
- def self.natural_sort(collection, options={})
84
- if block_given?
85
- Rearmed::Exceptions::BlockFoundError
86
- else
87
- collection.sort do |a,b|
88
- if options[:reverse] == true
89
- self.naturalize_str(b.to_s) <=> self.naturalize_str(a.to_s)
120
+ def self.select_map(collection)
121
+ if collection.is_a?(::Enumerable)
122
+ if block_given?
123
+ collection.select{|x| yield(x) }.map{|x| yield(x) }
90
124
  else
91
- self.naturalize_str(a.to_s) <=> self.naturalize_str(b.to_s)
125
+ collection.select.map
92
126
  end
127
+ else
128
+ raise TypeError.new("Invalid object passed to #{__method__}, must be an Enumerable")
93
129
  end
94
130
  end
95
- end
96
131
 
97
- def self.select_map(collection)
98
- if block_given?
99
- collection.select{|x| yield(x) }.map{|x| yield(x) }
100
- else
101
- collection.select.map
132
+ private
133
+
134
+ def self._naturalize_str(str)
135
+ str.to_s.split(/(\d+)/).map{|a| a =~ /\d+/ ? a.to_i : a}
102
136
  end
103
137
  end
104
138
 
105
- def self.to_bool(str)
106
- if str =~ /^(true|1|t|T)$/
107
- true
108
- elsif str =~ /^(false|0|f|F)$/
109
- false
110
- else
111
- nil
139
+ module String
140
+ def self.to_bool(str)
141
+ if str.is_a?(::String)
142
+ if str =~ /^(true|1|t|T)$/
143
+ true
144
+ elsif str =~ /^(false|0|f|F)$/
145
+ false
146
+ else
147
+ nil
148
+ end
149
+ else
150
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a String")
151
+ end
112
152
  end
113
- end
114
153
 
115
- def self.valid_integer?(str)
116
- str =~ /^\d*$/ ? true : false
117
- end
154
+ def self.valid_integer?(str)
155
+ if str.is_a?(::String)
156
+ str =~ /^\d*$/ ? true : false
157
+ else
158
+ raise TypeError.new("Invalid object passed to #{__method__}")
159
+ end
160
+ end
118
161
 
119
- def self.valid_float?(str)
120
- str =~ /(^(\d+)(\.)?(\d+)?$)|(^(\d+)?(\.)(\d+)$)/ ? true : false
121
- end
162
+ def self.valid_float?(str)
163
+ if str.is_a?(::String)
164
+ str =~ /(^(\d+)(\.)?(\d+)?$)|(^(\d+)?(\.)(\d+)$)/ ? true : false
165
+ else
166
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a String")
167
+ end
168
+ end
122
169
 
123
- private
124
-
125
- def self.naturalize_str(str)
126
- str.to_s.split(/(\d+)/).map{|a| a =~ /\d+/ ? a.to_i : a}
170
+ def self.casecmp?(str1, str2)
171
+ if str1.is_a?(::String)
172
+ if str2.is_a?(::String)
173
+ return str1.casecmp(str2) == 0
174
+ end
175
+ else
176
+ raise TypeError.new("Invalid object passed to #{__method__}, must be a String")
177
+ end
178
+ end
127
179
  end
128
180
 
129
181
  end