rearmed 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +8 -0
- data/LICENSE +7 -0
- data/README.md +151 -0
- data/Rakefile +13 -0
- data/lib/generators/rearmed/setup_generator.rb +56 -0
- data/lib/rearmed.rb +151 -0
- data/lib/rearmed/apply_patches.rb +8 -0
- data/lib/rearmed/monkey_patches/array.rb +29 -0
- data/lib/rearmed/monkey_patches/date.rb +9 -0
- data/lib/rearmed/monkey_patches/enumerable.rb +19 -0
- data/lib/rearmed/monkey_patches/hash.rb +23 -0
- data/lib/rearmed/monkey_patches/object.rb +18 -0
- data/lib/rearmed/monkey_patches/rails_3.rb +71 -0
- data/lib/rearmed/monkey_patches/rails_4.rb +143 -0
- data/lib/rearmed/monkey_patches/string.rb +22 -0
- data/lib/rearmed/version.rb +3 -0
- data/test/tc_rearmed.rb +33 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8fa0d5cedc04978a85f2c4a0fb6513c901433e91
|
4
|
+
data.tar.gz: 1bdae7cb97e455015685cb4892d8efbbf979d7ad
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2d5e3761d13a41c5fad2891d6c06b012e718466ae2ac2134bb16d8f140f143bb7835913dff9d79f5516fa33887623c2f37c42c45d8f7fa84c1e00236f7d0f152
|
7
|
+
data.tar.gz: fe28bd2d924cc1af47222b82e69ba4ba1aefd8c154e0486b27ee0aadd51415c8cfb335b025756ed0c9056465f655868ae329860196c3c2b3511dfecc2e47e536
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2016 Weston Ganger
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# Rearmed Ruby
|
2
|
+
<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
|
+
|
4
|
+
A collection of helpful methods and monkey patches for Objects, Strings, Enumerables, Arrays, Hash, Dates, & Rails
|
5
|
+
|
6
|
+
The difference between this library and others is that all monkey patching is performed in an opt-in way because you shouldnt be using methods you dont know about anyways.
|
7
|
+
|
8
|
+
For applicable methods I have placed the implementation inside the Rearmed module so if you don't like monkey patching or are working on the project with a team then you can use these methods instead. You can see how to use this implementation below the relevant methods here in the readme.
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
# Gemfile
|
12
|
+
|
13
|
+
gem 'rearmed'
|
14
|
+
```
|
15
|
+
|
16
|
+
Run `rails g rearmed:setup` to create a settings files in `config/initializers/rearmed.rb` where you can opt-in to the monkey patches available in the library. Set these values to true if you want to enable the applicable monkey patch.
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# config/initializers/rearmed.rb
|
20
|
+
|
21
|
+
Rearmed.enabled_patches = {
|
22
|
+
rails_4: {
|
23
|
+
or: false,
|
24
|
+
link_to_confirm: false,
|
25
|
+
find_relation_each: false,
|
26
|
+
find_in_relation_batches: false,
|
27
|
+
},
|
28
|
+
rails_3: {
|
29
|
+
hash_compact: false,
|
30
|
+
pluck: false,
|
31
|
+
update_columns: false,
|
32
|
+
all: false,
|
33
|
+
},
|
34
|
+
string: {
|
35
|
+
to_bool: false,
|
36
|
+
valid_integer: false,
|
37
|
+
valid_float: false
|
38
|
+
},
|
39
|
+
hash: {
|
40
|
+
only: false,
|
41
|
+
dig: false
|
42
|
+
},
|
43
|
+
array: {
|
44
|
+
dig: false,
|
45
|
+
delete_first: false
|
46
|
+
},
|
47
|
+
enumerable: {
|
48
|
+
natural_sort: false,
|
49
|
+
natural_sort_by: false
|
50
|
+
},
|
51
|
+
object: {
|
52
|
+
in: false,
|
53
|
+
not_nil: false
|
54
|
+
},
|
55
|
+
date: {
|
56
|
+
now: false
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
require 'rearmed/apply_patches'
|
61
|
+
```
|
62
|
+
|
63
|
+
### Object
|
64
|
+
```ruby
|
65
|
+
my_var.not_nil?
|
66
|
+
my_var.in?([1,2,3])
|
67
|
+
my_var.in?(1,2,3) # or with splat arguments
|
68
|
+
```
|
69
|
+
|
70
|
+
### String
|
71
|
+
```ruby
|
72
|
+
'123'.valid_integer?
|
73
|
+
# or without monkey patch: Rearmed.valid_integer?('123')
|
74
|
+
|
75
|
+
'123.123'.valid_float?
|
76
|
+
# or without monkey patch: Rearmed.valid_float?('123')
|
77
|
+
|
78
|
+
'true'.to_bool
|
79
|
+
# or without monkey patch: Rearmed.to_bool('true')
|
80
|
+
```
|
81
|
+
|
82
|
+
### Date
|
83
|
+
```ruby
|
84
|
+
Date.now
|
85
|
+
```
|
86
|
+
|
87
|
+
### Enumerable Methods (Array, Hash, etc.)
|
88
|
+
```ruby
|
89
|
+
items = ['1.1', '1.11', '1.2']
|
90
|
+
items.natural_sort
|
91
|
+
items.natural_sort(reverse: true) # because natural_sort does not accept a block
|
92
|
+
# or without monkey patch: Rearmed.natural_sort(items) or Rearmed.natural_sort(items, reverse: true)
|
93
|
+
|
94
|
+
items = ['1.1', '1.11', '1.2']
|
95
|
+
items.natural_sort{|a,b| b <=> a}
|
96
|
+
# or without monkey patch: Rearmed.natural_sort(items){|a,b| b <=> a}
|
97
|
+
|
98
|
+
items = [{version: "1.1"}, {version: "1.11"}, {version: "1.2"}]
|
99
|
+
items.natural_sort_by{|x| x[:version]}
|
100
|
+
# or without monkey patch: Rearmed.natural_sort_by(items){|x| x[:version]}
|
101
|
+
|
102
|
+
# Only available on array and hash in Ruby 2.2.x or below
|
103
|
+
items = [{foo: ['foo','bar']}, {test: 'thing'}]
|
104
|
+
items.dig(1, :foo, 2) # => 'bar'
|
105
|
+
# or without monkey patch: Rearmed.dig(items){|x| x[:version]}
|
106
|
+
```
|
107
|
+
|
108
|
+
### Array Methods
|
109
|
+
```ruby
|
110
|
+
array = [1,2,1,4,1]
|
111
|
+
array.delete_first(1) # => 1
|
112
|
+
puts array #=> [2,1,4,1]
|
113
|
+
array.delete_first{|x| 1 == x} # => 1
|
114
|
+
puts array # => [2,4,1]
|
115
|
+
array.delete_first # => 2
|
116
|
+
puts array # => [4,1]
|
117
|
+
```
|
118
|
+
|
119
|
+
### Hash Methods
|
120
|
+
```ruby
|
121
|
+
hash = {foo: 'foo', bar: 'bar', other: 'other'}
|
122
|
+
hash.only(:foo, :bar) # => {foo: 'foo'}
|
123
|
+
# or without monkey patch: Rearmed.only(hash, :foo, :bar)
|
124
|
+
|
125
|
+
hash.only!(:foo, :bar)
|
126
|
+
```
|
127
|
+
|
128
|
+
### Rails
|
129
|
+
|
130
|
+
##### Rails 3.x Backports
|
131
|
+
```ruby
|
132
|
+
my_hash.compact
|
133
|
+
my_hash.compact!
|
134
|
+
Post.all # Now returns AR relation
|
135
|
+
Post.first.update_columns(a: 'foo', b: 'bar')
|
136
|
+
Post.pluck(:name, :id) # adds multi column pluck support ex. => [['first', 1], ['second', 2], ['third', 3]]
|
137
|
+
```
|
138
|
+
|
139
|
+
|
140
|
+
##### Rails 4.x Backports & Additional Methods
|
141
|
+
```ruby
|
142
|
+
Post.where(name: 'foo').or.where(content: 'bar')
|
143
|
+
= link_to 'Delete', post_path(post), method: :delete, confirm: "Are you sure you want to delete this post?" #returns rails 3 behaviour of allowing confirm attribute as well as data-confirm
|
144
|
+
Post.find_in_relation_batches # this returns a relation instead of an array
|
145
|
+
Post.find_relation_each # this returns a relation instead of an array
|
146
|
+
```
|
147
|
+
|
148
|
+
# Credits
|
149
|
+
Created by Weston Ganger - @westonganger
|
150
|
+
|
151
|
+
<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>
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/lib/rearmed/version.rb')
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
|
+
task :test do
|
5
|
+
require 'rake/testtask'
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.test_files = FileList['test/**/tc_*.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
task default: :test
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Rearmed
|
4
|
+
class SetupGenerator < Rails::Generators::Base
|
5
|
+
|
6
|
+
def setup
|
7
|
+
contents = <<eos
|
8
|
+
Rearmed.enabled_patches = {
|
9
|
+
rails_4: {
|
10
|
+
find_relation_each: false,
|
11
|
+
find_in_relation_batches: false,
|
12
|
+
or: false,
|
13
|
+
link_to_confirm: false
|
14
|
+
},
|
15
|
+
rails_3: {
|
16
|
+
hash_compact: false,
|
17
|
+
pluck: false,
|
18
|
+
update_columns: false,
|
19
|
+
all: false
|
20
|
+
},
|
21
|
+
string: {
|
22
|
+
to_bool: false,
|
23
|
+
valid_integer: false,
|
24
|
+
valid_float: false
|
25
|
+
},
|
26
|
+
hash: {
|
27
|
+
only: false,
|
28
|
+
dig: false
|
29
|
+
},
|
30
|
+
array: {
|
31
|
+
index_all: false,
|
32
|
+
find: false,
|
33
|
+
dig: false,
|
34
|
+
delete_first: false
|
35
|
+
},
|
36
|
+
enumerable: {
|
37
|
+
natural_sort: false,
|
38
|
+
natural_sort_by: false
|
39
|
+
},
|
40
|
+
object: {
|
41
|
+
in: false,
|
42
|
+
not_nil: false
|
43
|
+
},
|
44
|
+
date: {
|
45
|
+
now: false
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
require 'rearmed/apply_patches'
|
50
|
+
eos
|
51
|
+
|
52
|
+
create_file "config/initializers/rearmed.rb", contents
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/rearmed.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
module Rearmed
|
2
|
+
|
3
|
+
@enabled_patches = {
|
4
|
+
rails_4: {
|
5
|
+
or: false,
|
6
|
+
link_to_confirm: false,
|
7
|
+
find_relation_each: false,
|
8
|
+
find_in_relation_batches: false
|
9
|
+
},
|
10
|
+
rails_3: {
|
11
|
+
hash_compact: false,
|
12
|
+
pluck: false,
|
13
|
+
update_columns: false,
|
14
|
+
all: false
|
15
|
+
},
|
16
|
+
string: {
|
17
|
+
to_bool: false,
|
18
|
+
valid_integer: false,
|
19
|
+
valid_float: false
|
20
|
+
},
|
21
|
+
hash: {
|
22
|
+
only: false,
|
23
|
+
dig: false
|
24
|
+
},
|
25
|
+
array: {
|
26
|
+
dig: false,
|
27
|
+
delete_first: false
|
28
|
+
},
|
29
|
+
enumerable: {
|
30
|
+
natural_sort: false,
|
31
|
+
natural_sort_by: false
|
32
|
+
},
|
33
|
+
object: {
|
34
|
+
in: false,
|
35
|
+
not_nil: false
|
36
|
+
},
|
37
|
+
date: {
|
38
|
+
now: false
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
def self.enabled_patches=(val)
|
43
|
+
@enabled_patches = val
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.enabled_patches
|
47
|
+
@enabled_patches
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.valid_integer?(str)
|
51
|
+
str =~ /^\d*$/ ? true : false
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.valid_float?(str)
|
55
|
+
str =~ /(^(\d+)(\.)?(\d+)?$)|(^(\d+)?(\.)(\d+)$)/ ? true : false
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.to_bool(str)
|
59
|
+
if str =~ /^true$/
|
60
|
+
true
|
61
|
+
elsif str =~ /^false$/
|
62
|
+
false
|
63
|
+
else
|
64
|
+
#raise(ArgumentError.new "incorrect element #{str}")
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.natural_sort_by(array)
|
70
|
+
array.sort_by{|x| self.naturalize_str(yield(x))}
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.natural_sort(array, options={})
|
74
|
+
if block_given?
|
75
|
+
BlockFoundError
|
76
|
+
else
|
77
|
+
array.sort do |a,b|
|
78
|
+
if options[:reverse] == true
|
79
|
+
self.naturalize_str(b.to_s) <=> self.naturalize_str(a.to_s)
|
80
|
+
else
|
81
|
+
self.naturalize_str(a.to_s) <=> self.naturalize_str(b.to_s)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.only(hash, *keys)
|
88
|
+
keys.map!{|key| hash.convert_key(key)} if hash.respond_to?(:convert_key, true)
|
89
|
+
keys.each_with_object(hash.class.new){|k, new_hash| new_hash[k] = hash[k] if hash.has_key?(k)}
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.dig(collection, *values)
|
93
|
+
current_val = nil
|
94
|
+
current_collection = collection
|
95
|
+
values.each_with_index do |val,i|
|
96
|
+
if i+1 == values.length
|
97
|
+
if (current_collection.is_a?(Array) && val.is_a?(Integer)) || (current_collection.is_a?(Hash) && ['String','Symbol'].include?(val.class.name))
|
98
|
+
current_val = current_collection[val]
|
99
|
+
else
|
100
|
+
current_val = nil
|
101
|
+
end
|
102
|
+
elsif current_collection.is_a?(Array)
|
103
|
+
if val.is_a?(Integer)
|
104
|
+
current_collection = current_collection[val]
|
105
|
+
next
|
106
|
+
else
|
107
|
+
current_val = nil
|
108
|
+
break
|
109
|
+
end
|
110
|
+
elsif current_collection.is_a?(Hash)
|
111
|
+
if ['Symbol','String'].include?(val.class.name)
|
112
|
+
current_collection = current_collection[val]
|
113
|
+
next
|
114
|
+
else
|
115
|
+
current_val = nil
|
116
|
+
break
|
117
|
+
end
|
118
|
+
else
|
119
|
+
current_val = nil
|
120
|
+
break
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
return current_val
|
125
|
+
end
|
126
|
+
|
127
|
+
class BlockFoundError < StandardError
|
128
|
+
def initialize(klass=nil)
|
129
|
+
super("Rearmed doesn't yet support a block on this method.")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class NoArgOrBlockGivenError < StandardError
|
134
|
+
def initialize(klass=nil)
|
135
|
+
super("Must pass an argument or a block.")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class BothArgAndBlockError < StandardError
|
140
|
+
def initialize(klass=nil)
|
141
|
+
super("Arguments and blocks must be used seperately.")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def self.naturalize_str(str)
|
148
|
+
str.to_s.split(/(\d+)/).map{|a| a =~ /\d+/ ? a.to_i : a}
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'rearmed/monkey_patches/object'
|
2
|
+
require 'rearmed/monkey_patches/string'
|
3
|
+
require 'rearmed/monkey_patches/array'
|
4
|
+
require 'rearmed/monkey_patches/hash'
|
5
|
+
require 'rearmed/monkey_patches/enumerable'
|
6
|
+
require 'rearmed/monkey_patches/rails_3'
|
7
|
+
require 'rearmed/monkey_patches/rails_4'
|
8
|
+
require 'rearmed/monkey_patches/date'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
array_enabled = Rearmed.enabled_patches[:array] == true
|
2
|
+
|
3
|
+
Array.module_eval do
|
4
|
+
if array_enabled || Rearmed.dig(Rearmed.enabled_patches, :array, :not_empty) == true
|
5
|
+
def not_empty?
|
6
|
+
!empty?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
if array_enabled || Rearmed.dig(Rearmed.enabled_patches, :array, :delete_first) == true
|
11
|
+
def delete_first(item = (no_arg_passed = true; nil))
|
12
|
+
if block_given? && !no_arg_passed
|
13
|
+
raise BothArgAndBlockError
|
14
|
+
elsif block_given?
|
15
|
+
self.delete_at(self.index{|x| yield(x)})
|
16
|
+
elsif item || !no_arg_passed
|
17
|
+
self.delete_at(self.index(item) || array.length)
|
18
|
+
else
|
19
|
+
self.delete_at(0)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if RUBY_VERSION.to_f < 2.3 && array_enabled || Rearmed.dig(Rearmed.enabled_patches, :array, :dig) == true
|
25
|
+
def dig(*args)
|
26
|
+
Rearmed.dig(self, *args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
enumerable_enabled = Rearmed.enabled_patches[:enumerable] == true
|
2
|
+
|
3
|
+
Enumerable.module_eval do
|
4
|
+
if enumerable_enabled || Rearmed.dig(Rearmed.enabled_patches, :enumerable, :natural_sort_by) == true
|
5
|
+
def natural_sort_by
|
6
|
+
Rearmed.natural_sort_by(self){|x| yield(x)}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
if enumerable_enabled || Rearmed.dig(Rearmed.enabled_patches, :enumerable, :natural_sort) == true
|
11
|
+
def natural_sort(options={})
|
12
|
+
if block_given?
|
13
|
+
Rearmed.natural_sort(self, options){|x| yield(x)}
|
14
|
+
else
|
15
|
+
Rearmed.natural_sort(self, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
hash_enabled = Rearmed.enabled_patches[:hash] == true
|
2
|
+
|
3
|
+
Hash.class_eval do
|
4
|
+
if hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :only) == true
|
5
|
+
def only(*keys)
|
6
|
+
Rearmed.only(self, *keys)
|
7
|
+
end
|
8
|
+
|
9
|
+
def only!(*keys)
|
10
|
+
keys.map!{ |key| convert_key(key) } if respond_to?(:convert_key, true)
|
11
|
+
omit = only(*self.keys - keys)
|
12
|
+
hash = only(*keys)
|
13
|
+
replace(hash)
|
14
|
+
omit
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if RUBY_VERSION.to_f < 2.3 && hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :dig) == true
|
19
|
+
def dig(*args)
|
20
|
+
Rearmed.dig(self, *args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
object_enabled = Rearmed.enabled_patches[:object] == true
|
2
|
+
|
3
|
+
Object.class_eval do
|
4
|
+
if object_enabled || Rearmed.dig(Rearmed.enabled_patches, :object, :not_nil) == true
|
5
|
+
def not_nil?
|
6
|
+
!nil?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
if object_enabled || Rearmed.dig(Rearmed.enabled_patches, :object, :in) == true
|
11
|
+
def in?(array, *more)
|
12
|
+
if !more.empty?
|
13
|
+
array = [array, *more]
|
14
|
+
end
|
15
|
+
array.include?(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
rails_3_enabled = Rearmed.enabled_patches[:rails_3] == true
|
2
|
+
|
3
|
+
if defined?(ActiveSupport) && ActiveSupport::VERSION::MAJOR < 4
|
4
|
+
if rails_3_enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :hash_compact) == true
|
5
|
+
Hash.class_eval do
|
6
|
+
def compact
|
7
|
+
self.select{|_, value| !value.nil?}
|
8
|
+
end
|
9
|
+
|
10
|
+
def compact!
|
11
|
+
self.reject!{|_, value| value.nil?}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if defined?(ActiveRecord) && ActiveRecord::VERSION::MAJOR < 4
|
18
|
+
|
19
|
+
if rails_3_enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :all) == true
|
20
|
+
ActiveRecord::FinderMethods.module_eval do
|
21
|
+
def all(*args)
|
22
|
+
args.any? ? apply_finder_options(args.first) : self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if rails_3_enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :update_columns) == true
|
28
|
+
ActiveRecord::Persistence::ClassMethods.module_eval do
|
29
|
+
def update_columns(attributes)
|
30
|
+
raise ActiveRecordError, "cannot update a new record" if new_record?
|
31
|
+
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
32
|
+
|
33
|
+
attributes.each_key do |key|
|
34
|
+
raise ActiveRecordError, "#{key.to_s} is marked as readonly" if self.class.readonly_attributes.include?(key.to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
|
38
|
+
|
39
|
+
attributes.each do |k, v|
|
40
|
+
raw_write_attribute(k, v)
|
41
|
+
end
|
42
|
+
|
43
|
+
updated_count == 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if rails_3_enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :pluck) == true
|
49
|
+
ActiveRecord::Relation.class_eval do
|
50
|
+
def pluck(*args)
|
51
|
+
args.map! do |column_name|
|
52
|
+
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
|
53
|
+
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
|
54
|
+
else
|
55
|
+
column_name.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
relation = clone
|
60
|
+
relation.select_values = args
|
61
|
+
klass.connection.select_all(relation.arel).map! do |attributes|
|
62
|
+
initialized_attributes = klass.initialize_attributes(attributes)
|
63
|
+
attributes.map do |key, attr|
|
64
|
+
klass.type_cast_attribute(key, initialized_attributes)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
enabled = Rearmed.enabled_patches[:rails_4] == true
|
2
|
+
|
3
|
+
if defined?(ActionView) && enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_4, :link_to_confirm) == true
|
4
|
+
ActionView::Helpers::UrlHelper.module_eval do
|
5
|
+
def convert_options_to_data_attributes(options, html_options)
|
6
|
+
if html_options
|
7
|
+
html_options = html_options.stringify_keys
|
8
|
+
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
|
9
|
+
|
10
|
+
method = html_options.delete('method')
|
11
|
+
add_method_to_attributes!(html_options, method) if method
|
12
|
+
|
13
|
+
### CUSTOM - behave like Rails 3.2
|
14
|
+
confirm = html_options.delete('confirm')
|
15
|
+
html_options['data-confirm'] = confirm if confirm
|
16
|
+
|
17
|
+
html_options
|
18
|
+
else
|
19
|
+
link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
if defined?(ActiveRecord)
|
26
|
+
|
27
|
+
ActiveRecord::Batches.module_eval do
|
28
|
+
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_4, :find_in_relation_batches) == true
|
29
|
+
def find_in_relation_batches(options = {})
|
30
|
+
options.assert_valid_keys(:start, :batch_size)
|
31
|
+
|
32
|
+
relation = self
|
33
|
+
start = options[:start]
|
34
|
+
batch_size = options[:batch_size] || 1000
|
35
|
+
|
36
|
+
unless block_given?
|
37
|
+
return to_enum(:find_in_relation_batches, options) do
|
38
|
+
total = start ? where(table[primary_key].gteq(start)).size : size
|
39
|
+
(total - 1).div(batch_size) + 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if logger && (arel.orders.present? || arel.taken.present?)
|
44
|
+
logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
|
45
|
+
end
|
46
|
+
|
47
|
+
relation = relation.reorder(batch_order).limit(batch_size)
|
48
|
+
#records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
|
49
|
+
records = start ? relation.where(table[primary_key].gteq(start)) : relation
|
50
|
+
|
51
|
+
while records.any?
|
52
|
+
records_size = records.size
|
53
|
+
primary_key_offset = records.last.id
|
54
|
+
raise "Primary key not included in the custom select clause" unless primary_key_offset
|
55
|
+
|
56
|
+
yield records
|
57
|
+
|
58
|
+
break if records_size < batch_size
|
59
|
+
|
60
|
+
records = relation.where(table[primary_key].gt(primary_key_offset))#.to_a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_4, :find_relation_each) == true
|
66
|
+
def find_relation_each(options = {})
|
67
|
+
if block_given?
|
68
|
+
find_in_relation_batches(options) do |records|
|
69
|
+
records.each { |record| yield record }
|
70
|
+
end
|
71
|
+
else
|
72
|
+
enum_for :find_relation_each, options do
|
73
|
+
options[:start] ? where(table[primary_key].gteq(options[:start])).size : size
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_4, :or) == true
|
82
|
+
module ActiveRecord
|
83
|
+
module Querying
|
84
|
+
delegate :or, :to => :all
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module ActiveRecord
|
89
|
+
module QueryMethods
|
90
|
+
class OrChain
|
91
|
+
def initialize(scope)
|
92
|
+
@scope = scope
|
93
|
+
end
|
94
|
+
|
95
|
+
def method_missing(method, *args, &block)
|
96
|
+
right_relation = @scope.klass.unscoped do
|
97
|
+
@scope.klass.send(method, *args, &block)
|
98
|
+
end
|
99
|
+
@scope.or(right_relation)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Post.where("id = 1").or.where("id = 2")
|
104
|
+
# Post.where("id = 1").or.containing_the_letter_a
|
105
|
+
# Post.where("id = 1").or(Post.where("id = 2"))
|
106
|
+
# Post.where("id = 1").or("id = ?", 2)
|
107
|
+
def or(opts = :chain, *rest)
|
108
|
+
if opts == :chain
|
109
|
+
OrChain.new(self)
|
110
|
+
else
|
111
|
+
left = self
|
112
|
+
right = (ActiveRecord::Relation === opts) ? opts : klass.unscoped.where(opts, rest)
|
113
|
+
|
114
|
+
unless left.where_values.empty? || right.where_values.empty?
|
115
|
+
left.where_values = [left.where_ast.or(right.where_ast)]
|
116
|
+
right.where_values = []
|
117
|
+
end
|
118
|
+
|
119
|
+
left = left.merge(right)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns an Arel AST containing only where_values
|
124
|
+
def where_ast
|
125
|
+
arel_wheres = []
|
126
|
+
|
127
|
+
where_values.each do |where|
|
128
|
+
arel_wheres << (String === where ? Arel.sql(where) : where)
|
129
|
+
end
|
130
|
+
|
131
|
+
return Arel::Nodes::Grouping.new(Arel::Nodes::And.new(arel_wheres)) if arel_wheres.length >= 2
|
132
|
+
|
133
|
+
if Arel::Nodes::SqlLiteral === arel_wheres.first
|
134
|
+
Arel::Nodes::Grouping.new(arel_wheres.first)
|
135
|
+
else
|
136
|
+
arel_wheres.first
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
string_enabled = Rearmed.enabled_patches[:string] == true
|
2
|
+
|
3
|
+
String.class_eval do
|
4
|
+
if string_enabled || Rearmed.dig(Rearmed.enabled_patches, :string, :valid_integer) == true
|
5
|
+
def valid_integer?
|
6
|
+
Rearmed.valid_integer?(self)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
if string_enabled || Rearmed.dig(Rearmed.enabled_patches, :string, :valid_float) == true
|
11
|
+
def valid_float?
|
12
|
+
Rearmed.valid_float?(self)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
if string_enabled || Rearmed.dig(Rearmed.enabled_patches, :string, :to_bool) == true
|
17
|
+
def to_bool
|
18
|
+
Rearmed.to_bool(self)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
data/test/tc_rearmed.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
require 'yaml'
|
3
|
+
require 'minitest'
|
4
|
+
|
5
|
+
lib = File.expand_path('../lib', __FILE__)
|
6
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
7
|
+
require 'rearmed.rb'
|
8
|
+
|
9
|
+
require 'minitest/autorun'
|
10
|
+
|
11
|
+
class TestRearmed < MiniTest::Test
|
12
|
+
def setup
|
13
|
+
@array = ["1.1","1.11","1.2","1.22"]
|
14
|
+
@hash_array = [{version: "1.1"}, {version: "1.11"}, {version: "1.2"}, {version: "1.22"}]
|
15
|
+
@hash = {version_b: "1.1", version_a: "1.11", version_c: "1.2", version_d: "1.22"}
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_sort_enumerables_correctly
|
19
|
+
assert_equal [*@array], [@array.to_args]
|
20
|
+
|
21
|
+
assert_equal "1.2", @array.natural_sort[1]
|
22
|
+
assert_equal "1.22", @array.natural_sort{|a,b| b <=> a}[0]
|
23
|
+
assert_equal "1.2", @array.natural_sort_by{|x| x}[1]
|
24
|
+
|
25
|
+
assert_equal([:version_c, "1.2"], @hash.natural_sort_by{|x| x[1]}[1])
|
26
|
+
assert_equal([:version_c, "1.2"], @hash.natural_sort[1])
|
27
|
+
#assert_equal([:version_d, "1.22"], @hash.natural_sort{|a,b| b[1] <=> a[1]}[0])
|
28
|
+
|
29
|
+
#assert_equal({version: "1.2"}, @hash_array.natural_sort[1])
|
30
|
+
#assert_equal({version: "1.22"}, @hash_array.natural_sort{|a,b| b[:version] <=> a[:version]}[0])
|
31
|
+
#assert_equal({version: "1.2"}, @hash_array.natural_sort_by{|x| x[:version]}[1])
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rearmed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Weston Ganger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A collection of helpful methods and monkey patches for Objects, Strings,
|
56
|
+
Enumerables, Arrays, Hash, Dates, & Rails
|
57
|
+
email: westonganger@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- CHANGELOG.md
|
63
|
+
- LICENSE
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/generators/rearmed/setup_generator.rb
|
67
|
+
- lib/rearmed.rb
|
68
|
+
- lib/rearmed/apply_patches.rb
|
69
|
+
- lib/rearmed/monkey_patches/array.rb
|
70
|
+
- lib/rearmed/monkey_patches/date.rb
|
71
|
+
- lib/rearmed/monkey_patches/enumerable.rb
|
72
|
+
- lib/rearmed/monkey_patches/hash.rb
|
73
|
+
- lib/rearmed/monkey_patches/object.rb
|
74
|
+
- lib/rearmed/monkey_patches/rails_3.rb
|
75
|
+
- lib/rearmed/monkey_patches/rails_4.rb
|
76
|
+
- lib/rearmed/monkey_patches/string.rb
|
77
|
+
- lib/rearmed/version.rb
|
78
|
+
- test/tc_rearmed.rb
|
79
|
+
homepage: https://github.com/westonganger/rearmed_rb
|
80
|
+
licenses: []
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.9.3
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.5.1
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: A collection of helpful methods and monkey patches for Objects, Strings,
|
102
|
+
Enumerables, Arrays, Hash, Dates, & Rails
|
103
|
+
test_files:
|
104
|
+
- test/tc_rearmed.rb
|