rearmed 1.2.1 → 1.3.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +21 -114
- data/lib/rearmed/apply_patches.rb +0 -4
- data/lib/rearmed/default_enabled_patches.hash +16 -9
- data/lib/rearmed/methods.rb +10 -2
- data/lib/rearmed/monkey_patches/array.rb +1 -1
- data/lib/rearmed/monkey_patches/hash.rb +7 -8
- data/lib/rearmed/monkey_patches/object.rb +1 -1
- data/lib/rearmed/version.rb +1 -1
- data/test/tc_rearmed.rb +14 -84
- metadata +2 -7
- data/lib/generators/rearmed/setup_generator.rb +0 -15
- data/lib/rearmed/monkey_patches/minitest.rb +0 -35
- data/lib/rearmed/monkey_patches/rails.rb +0 -268
- data/lib/rearmed/monkey_patches/rails_3.rb +0 -57
- data/lib/rearmed/monkey_patches/rails_4.rb +0 -143
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a547fa7cd7259d77eee0a4707cd1cf9589e9aa2
|
4
|
+
data.tar.gz: a0be2f3e5e61f6c6ffb8da8213bfd9dd7b767b6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4fff0c4782edd10fee028e471469fa73ab5f8a0b8c0fa6a91f6debe23a9451e2afe7e45fe09c34ef9c6ad3b38686d5cb5f9fee199108706c6f86766279f429b
|
7
|
+
data.tar.gz: a6ba345629c2076c05c8fd219eddc4c4fe63772ebd683d81f967328759e1a88c1f862b636a27330f34df8dd0c5086901f74d0956ec68a7ce15cb8d98c9697183
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
---------
|
3
3
|
|
4
|
+
- **1.3.0 - Feb 28, 2017**
|
5
|
+
- Remove Rails and Minitest methods. Those methods moved to https://github.com/westonganger/rearmed_rails
|
6
|
+
- Change methods names of Rearmed namespaced hash methods to convey better meaning
|
7
|
+
- **1.2.2 - Feb 19, 2017**
|
8
|
+
- Add `field_is_array`, `options_for_select_include_blank`, `options_from_collect_for_select_include_blank`
|
9
|
+
- Namespace rails patches to active_record and other
|
4
10
|
- **1.2.1 - Jan 24, 2017**
|
5
11
|
- Add Hash `join`, `to_struct`
|
6
12
|
- Fix `find_duplicates`
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# Rearmed Ruby
|
2
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
3
|
|
4
|
-
A collection of helpful methods and monkey patches for Objects, Strings, Enumerables, Arrays, Hash, Dates
|
4
|
+
A collection of helpful methods and monkey patches for Objects, Strings, Enumerables, Arrays, Hash, Dates
|
5
|
+
|
6
|
+
I have recently extracted the Rails and Minitest monkey patches to another gem https://github.com/westonganger/rearmed_rails because the Rails methods are getting quite extensive.
|
5
7
|
|
6
8
|
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
9
|
|
8
|
-
|
10
|
+
When possible I have placed the method implementations 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 then skip the config and see how to use each implementation below the relevant methods documentation.
|
9
11
|
|
10
12
|
```ruby
|
11
13
|
# Gemfile
|
@@ -13,7 +15,9 @@ For applicable methods I have placed the implementation inside the Rearmed modul
|
|
13
15
|
gem 'rearmed'
|
14
16
|
```
|
15
17
|
|
16
|
-
|
18
|
+
# Usage
|
19
|
+
|
20
|
+
## Setup Enabled Monkey Patches (all are optional)
|
17
21
|
|
18
22
|
```ruby
|
19
23
|
# config/initializers/rearmed.rb
|
@@ -49,30 +53,6 @@ Rearmed.enabled_patches = {
|
|
49
53
|
to_bool: false,
|
50
54
|
valid_float: false,
|
51
55
|
valid_integer: false
|
52
|
-
},
|
53
|
-
minitest: {
|
54
|
-
assert_changed: false,
|
55
|
-
assert_not_changed: false
|
56
|
-
},
|
57
|
-
rails: {
|
58
|
-
find_duplicates: false,
|
59
|
-
find_in_relation_batches: false,
|
60
|
-
find_or_create: false,
|
61
|
-
find_relation_each: false,
|
62
|
-
newest: false,
|
63
|
-
pluck_to_hash: false,
|
64
|
-
pluck_to_struct: false,
|
65
|
-
reset_auto_increment: false,
|
66
|
-
reset_table: false
|
67
|
-
},
|
68
|
-
rails_4: {
|
69
|
-
link_to_confirm: false,
|
70
|
-
or: false
|
71
|
-
},
|
72
|
-
rails_3: {
|
73
|
-
all: false,
|
74
|
-
pluck: false,
|
75
|
-
update_columns: false
|
76
56
|
}
|
77
57
|
}
|
78
58
|
|
@@ -80,7 +60,7 @@ Rearmed.enabled_patches = {
|
|
80
60
|
require 'rearmed/apply_patches'
|
81
61
|
```
|
82
62
|
|
83
|
-
|
63
|
+
## Array Methods
|
84
64
|
```ruby
|
85
65
|
array = [1,2,1,4,1]
|
86
66
|
array.delete_first(1) # => 1
|
@@ -98,7 +78,7 @@ items.dig(0, :foo, 1) # => 'bar'
|
|
98
78
|
# or without monkey patch: Rearmed.dig(items, 0, :foo, 1)
|
99
79
|
```
|
100
80
|
|
101
|
-
|
81
|
+
## Enumerable Methods (Array, Hash, etc.)
|
102
82
|
```ruby
|
103
83
|
items = ['1.1', '1.11', '1.2']
|
104
84
|
items.natural_sort
|
@@ -110,42 +90,45 @@ items.natural_sort_by{|x| x[:version]}
|
|
110
90
|
# or without monkey patch: Rearmed.natural_sort_by(items){|x| x[:version]}
|
111
91
|
```
|
112
92
|
|
113
|
-
|
93
|
+
## Date
|
114
94
|
```ruby
|
115
95
|
Date.now
|
116
96
|
```
|
117
97
|
|
118
|
-
|
98
|
+
## Hash Methods
|
119
99
|
```ruby
|
120
|
-
my_hash.compact
|
121
|
-
my_hash.compact!
|
122
|
-
|
123
100
|
hash.join{|k,v| "#{k}: #{v}\n"}
|
124
101
|
|
125
102
|
hash = {foo: 'foo', bar: 'bar', other: 'other'}
|
126
103
|
hash.only(:foo, :bar) # => {foo: 'foo'}
|
127
|
-
# or without monkey patch: Rearmed.
|
104
|
+
# or without monkey patch: Rearmed.hash_only(hash, :foo, :bar)
|
128
105
|
|
129
106
|
hash.only!(:foo, :bar)
|
130
107
|
|
131
108
|
hash.to_struct
|
109
|
+
# or without monkey patch: Rearmed.hash_to_struct(hash)
|
132
110
|
|
133
111
|
# Only available on array and hash in Ruby 2.2.x or below
|
134
112
|
items = [{foo: ['foo','bar']}, {test: 'thing'}]
|
135
113
|
items.dig(0, :foo, 1) # => 'bar'
|
136
114
|
# or without monkey patch: Rearmed.dig(items, 0, :foo, 1)
|
115
|
+
|
116
|
+
# Only available on array and hash in Ruby 2.3.x or below
|
117
|
+
hash.compact
|
118
|
+
# or without monkey patch: Rearmed.hash_compact(hash)
|
119
|
+
hash.compact!
|
137
120
|
```
|
138
121
|
|
139
|
-
|
122
|
+
## Object
|
140
123
|
```ruby
|
141
124
|
my_var.not_nil?
|
142
125
|
|
143
|
-
#
|
126
|
+
# In ActiveSupport / Rails this is not patched as this method is already defined there
|
144
127
|
my_var.in?([1,2,3])
|
145
128
|
my_var.in?(1,2,3) # or with splat arguments
|
146
129
|
```
|
147
130
|
|
148
|
-
|
131
|
+
## String
|
149
132
|
```ruby
|
150
133
|
'123'.valid_integer?
|
151
134
|
# or without monkey patch: Rearmed.valid_integer?('123')
|
@@ -162,87 +145,11 @@ my_var.in?(1,2,3) # or with splat arguments
|
|
162
145
|
'bar'.ends_with?('ar') # => true
|
163
146
|
```
|
164
147
|
|
165
|
-
### Minitest Methods
|
166
|
-
```ruby
|
167
|
-
assert_changed 'user.name' do
|
168
|
-
user.name = "Bob"
|
169
|
-
end
|
170
|
-
|
171
|
-
assert_not_changed -> { user.name } do
|
172
|
-
user.update(user_params)
|
173
|
-
end
|
174
|
-
|
175
|
-
assert_not_changed lambda{ user.name } do
|
176
|
-
user.update(user_params)
|
177
|
-
end
|
178
|
-
```
|
179
|
-
|
180
|
-
### Rails
|
181
|
-
|
182
|
-
##### Additional ActiveRecord Methods
|
183
|
-
Note: All methods which involve deletion are compatible with Paranoia & ActsAsParanoid
|
184
|
-
|
185
|
-
```ruby
|
186
|
-
Post.pluck_to_hash(:name, :category, :id)
|
187
|
-
Post.pluck_to_struct(:name, :category, :id)
|
188
|
-
|
189
|
-
Post.find_or_create(name: 'foo', content: 'bar') # use this instead of the super confusing first_or_create method
|
190
|
-
Post.find_or_create!(name: 'foo', content: 'bar')
|
191
|
-
|
192
|
-
Post.find_duplicates # return active record relation of all records that have duplicates. By default it skips the primary_key, created_at, updated_at, & deleted_at columns
|
193
|
-
Post.find_duplicates(:name) # find duplicates based on the name attribute
|
194
|
-
Post.find_duplicates(:name, :category) # find duplicates based on the name & category attribute
|
195
|
-
Post.find_duplicates(self.column_names.reject{|x| ['id','created_at','updated_at','deleted_at'].include?(x)})
|
196
|
-
|
197
|
-
# It also can delete duplicates. Valid values for keep are :first & :last. Valid values for delete_method are :destroy & :delete. soft_delete is only used if you are using acts_as_paranoid on your model.
|
198
|
-
Post.find_duplicates(:name, :category, delete: true)
|
199
|
-
Post.find_duplicates(:name, :category, delete: {keep: :first, delete_method: :destroy, soft_delete: true}) # these are the default settings for delete: true
|
200
|
-
|
201
|
-
Post.newest # get the newest post, by default ordered by :created_at
|
202
|
-
Post.newest(:updated_at) # different sort order
|
203
|
-
Post.newest(:published_at, :created_at) # multiple columns to sort on
|
204
|
-
|
205
|
-
Post.reset_table # delete all records from table and reset autoincrement column (id), works with mysql/mariadb/postgresql/sqlite
|
206
|
-
# or with options
|
207
|
-
Post.reset_table(delete_method: :destroy) # to ensure all callbacks are fired
|
208
|
-
|
209
|
-
Post.reset_auto_increment # reset mysql/mariadb/postgresql/sqlite auto-increment column, if contains records then defaults to starting from next available number
|
210
|
-
# or with options
|
211
|
-
Post.reset_auto_increment(value: 1, column: :id) # column option is only relevant for postgresql
|
212
|
-
|
213
|
-
Post.find_in_relation_batches # this returns a relation instead of an array
|
214
|
-
Post.find_relation_each # this returns a relation instead of an array
|
215
|
-
```
|
216
|
-
|
217
|
-
##### Rails 4.x Backports
|
218
|
-
```ruby
|
219
|
-
# returns to rails 3 behaviour of allowing confirm attribute as well as data-confirm
|
220
|
-
= link_to 'Delete', post_path(post), method: :delete, confirm: "Are you sure you want to delete this post?"
|
221
|
-
|
222
|
-
# This version of `or` behaves way nicer than the one implemented in Rails 5, it allows you to do what you need.
|
223
|
-
# However this patch does not work in Rails 5+
|
224
|
-
Post.where(name: 'foo').or.where(content: 'bar')
|
225
|
-
Post.where(name: 'foo').or.my_custom_scope
|
226
|
-
Post.where(name: 'foo').or(Post.where(content: 'bar'))
|
227
|
-
Post.where(name: 'foo).or(content: 'bar')
|
228
|
-
```
|
229
|
-
|
230
|
-
##### Rails 3.x Backports
|
231
|
-
```ruby
|
232
|
-
Post.all # Now returns AR relation
|
233
|
-
Post.first.update_columns(a: 'foo', b: 'bar')
|
234
|
-
Post.pluck(:name, :id) # adds multi column pluck support ex. => [['first', 1], ['second', 2], ['third', 3]]
|
235
|
-
|
236
|
-
my_hash.compact # See Hash methods above
|
237
|
-
my_hash.compact!
|
238
|
-
```
|
239
|
-
|
240
148
|
# Contributing / Todo
|
241
149
|
If you want to request a method please raise an issue and we can discuss the implementation.
|
242
150
|
|
243
151
|
If you want to contribute here are a couple of things you could do:
|
244
152
|
|
245
|
-
- Add Tests for Rails methods
|
246
153
|
- Get the `natural_sort` method to accept a block
|
247
154
|
|
248
155
|
|
@@ -3,8 +3,4 @@ require 'rearmed/monkey_patches/string'
|
|
3
3
|
require 'rearmed/monkey_patches/array'
|
4
4
|
require 'rearmed/monkey_patches/hash'
|
5
5
|
require 'rearmed/monkey_patches/enumerable'
|
6
|
-
require 'rearmed/monkey_patches/rails'
|
7
|
-
require 'rearmed/monkey_patches/rails_3'
|
8
|
-
require 'rearmed/monkey_patches/rails_4'
|
9
6
|
require 'rearmed/monkey_patches/date'
|
10
|
-
require 'rearmed/monkey_patches/minitest'
|
@@ -35,15 +35,22 @@
|
|
35
35
|
assert_not_changed: false
|
36
36
|
},
|
37
37
|
rails: {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
active_record: {
|
39
|
+
find_duplicates: false,
|
40
|
+
find_in_relation_batches: false,
|
41
|
+
find_or_create: false,
|
42
|
+
find_relation_each: false,
|
43
|
+
newest: false,
|
44
|
+
pluck_to_hash: false,
|
45
|
+
pluck_to_struct: false,
|
46
|
+
reset_auto_increment: false,
|
47
|
+
reset_table: false
|
48
|
+
},
|
49
|
+
other: {
|
50
|
+
field_is_array: false,
|
51
|
+
options_for_select_include_blank: false,
|
52
|
+
options_from_collection_for_select_include_blank: false
|
53
|
+
}
|
47
54
|
},
|
48
55
|
rails_4: {
|
49
56
|
link_to_confirm: false,
|
data/lib/rearmed/methods.rb
CHANGED
@@ -35,7 +35,7 @@ module Rearmed
|
|
35
35
|
return current_val
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.
|
38
|
+
def self.hash_join(hash, delimiter=', ', &block)
|
39
39
|
unless block_given?
|
40
40
|
block = -> (k,v) {
|
41
41
|
"#{k}: #{v}"
|
@@ -76,8 +76,12 @@ module Rearmed
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
79
|
+
|
80
|
+
def self.hash_compact(hash)
|
81
|
+
hash.reject{|_, value| value.nil?}
|
82
|
+
end
|
79
83
|
|
80
|
-
def self.
|
84
|
+
def self.hash_only(hash, *keys)
|
81
85
|
keys.map!{|key| hash.convert_key(key)} if hash.respond_to?(:convert_key, true)
|
82
86
|
keys.each_with_object(hash.class.new){|k, new_hash| new_hash[k] = hash[k] if hash.has_key?(k)}
|
83
87
|
end
|
@@ -100,6 +104,10 @@ module Rearmed
|
|
100
104
|
str =~ /(^(\d+)(\.)?(\d+)?$)|(^(\d+)?(\.)(\d+)$)/ ? true : false
|
101
105
|
end
|
102
106
|
|
107
|
+
def self.hash_to_struct(hash)
|
108
|
+
Struct.new(*hash.keys).new(*hash.values)
|
109
|
+
end
|
110
|
+
|
103
111
|
private
|
104
112
|
|
105
113
|
def self.naturalize_str(str)
|
@@ -21,7 +21,7 @@ Array.module_eval do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
if
|
24
|
+
if ![].respond_to?(:dig) && (array_enabled || Rearmed.dig(Rearmed.enabled_patches, :array, :dig))
|
25
25
|
def dig(*args)
|
26
26
|
Rearmed.dig(self, *args)
|
27
27
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
hash_enabled = Rearmed.enabled_patches[:hash] == true
|
2
2
|
|
3
3
|
Hash.class_eval do
|
4
|
-
|
5
|
-
if allowed && (hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :compact))
|
4
|
+
if !{}.respond_to?(:compact) && (hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :compact))
|
6
5
|
def compact
|
7
|
-
self
|
6
|
+
Rearmed.hash_compact(self)
|
8
7
|
end
|
9
8
|
|
10
9
|
def compact!
|
@@ -12,7 +11,7 @@ Hash.class_eval do
|
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
if
|
14
|
+
if !{}.respond_to?(:dig) && (hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :dig))
|
16
15
|
def dig(*args)
|
17
16
|
Rearmed.dig(self, *args)
|
18
17
|
end
|
@@ -21,16 +20,16 @@ Hash.class_eval do
|
|
21
20
|
if hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :join)
|
22
21
|
def join(delimiter=', ', &block)
|
23
22
|
if block_given?
|
24
|
-
Rearmed.
|
23
|
+
Rearmed.hash_join(self, delimiter, &block)
|
25
24
|
else
|
26
|
-
Rearmed.
|
25
|
+
Rearmed.hash_join(self, delimiter)
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
if hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :only)
|
32
31
|
def only(*keys)
|
33
|
-
Rearmed.
|
32
|
+
Rearmed.hash_only(self, *keys)
|
34
33
|
end
|
35
34
|
|
36
35
|
def only!(*keys)
|
@@ -44,7 +43,7 @@ Hash.class_eval do
|
|
44
43
|
|
45
44
|
if hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :to_struct)
|
46
45
|
def to_struct
|
47
|
-
|
46
|
+
Rearmed.hash_to_struct(self)
|
48
47
|
end
|
49
48
|
end
|
50
49
|
end
|
@@ -7,7 +7,7 @@ Object.class_eval do
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
if !
|
10
|
+
if !Object.new.respond_to?(:in?) && (object_enabled || Rearmed.dig(Rearmed.enabled_patches, :object, :in))
|
11
11
|
def in?(array, *more)
|
12
12
|
if !more.empty?
|
13
13
|
array = [array, *more]
|
data/lib/rearmed/version.rb
CHANGED
data/test/tc_rearmed.rb
CHANGED
@@ -58,10 +58,9 @@ class TestRearmed < MiniTest::Test
|
|
58
58
|
eql(str.to_bool, false)
|
59
59
|
|
60
60
|
str = 'not true'
|
61
|
-
|
61
|
+
assert_nil(str.to_bool)
|
62
62
|
|
63
63
|
|
64
|
-
# Test Rearmed methods (just cause really)
|
65
64
|
str = 'true'
|
66
65
|
eql(Rearmed.to_bool(str), true)
|
67
66
|
|
@@ -99,10 +98,10 @@ class TestRearmed < MiniTest::Test
|
|
99
98
|
array = [{foo: ['foo','bar']}, {test: 'thing'}]
|
100
99
|
|
101
100
|
eql(array.dig(0, :foo, 1), 'bar')
|
102
|
-
|
101
|
+
assert_nil(array.dig(0, :foo, 2))
|
103
102
|
|
104
103
|
eql(Rearmed.dig(array, 1, :test), 'thing')
|
105
|
-
|
104
|
+
assert_nil(Rearmed.dig(array, 1, :bar))
|
106
105
|
|
107
106
|
hash = {a: {foo: ['bar']}, b: {c: 'c'}}
|
108
107
|
|
@@ -135,10 +134,11 @@ class TestRearmed < MiniTest::Test
|
|
135
134
|
eql(hash, {foo: 'foo', bar: 'bar'})
|
136
135
|
|
137
136
|
hash = {foo: 'foo', bar: 'bar', other: 'other'}
|
138
|
-
eql(Rearmed.
|
137
|
+
eql(Rearmed.hash_only(hash, :foo, :bar), {foo: 'foo', bar: 'bar'})
|
139
138
|
|
140
139
|
hash = {foo: nil, bar: nil, other: 'other'}
|
141
140
|
eql(hash.compact, {other: 'other'})
|
141
|
+
eql(Rearmed.hash_compact(hash), {other: 'other'})
|
142
142
|
|
143
143
|
hash = {foo: nil, bar: nil, other: 'other'}
|
144
144
|
hash.compact!
|
@@ -149,16 +149,21 @@ class TestRearmed < MiniTest::Test
|
|
149
149
|
eql(hash.join('___'), "foo: bar___bar: foo")
|
150
150
|
eql(hash.join{|k,v| v}, "bar, foo")
|
151
151
|
eql(hash.join('___'){|k,v| v}, "bar___foo")
|
152
|
-
eql(Rearmed.
|
153
|
-
eql(Rearmed.
|
154
|
-
eql(Rearmed.
|
155
|
-
eql(Rearmed.
|
152
|
+
eql(Rearmed.hash_join(hash), "foo: bar, bar: foo")
|
153
|
+
eql(Rearmed.hash_join(hash, '___'), "foo: bar___bar: foo")
|
154
|
+
eql(Rearmed.hash_join(hash){|k,v| v}, "bar, foo")
|
155
|
+
eql(Rearmed.hash_join(hash, '___'){|k,v| v}, "bar___foo")
|
156
156
|
|
157
157
|
hash = {foo: :bar, bar: 'foo'}
|
158
158
|
struct = hash.to_struct
|
159
159
|
assert(struct.is_a?(Struct))
|
160
160
|
eql(struct.foo, :bar)
|
161
161
|
eql(struct.bar, 'foo')
|
162
|
+
|
163
|
+
struct = Rearmed.hash_to_struct(hash)
|
164
|
+
assert(struct.is_a?(Struct))
|
165
|
+
eql(struct.foo, :bar)
|
166
|
+
eql(struct.bar, 'foo')
|
162
167
|
end
|
163
168
|
|
164
169
|
def test_object
|
@@ -190,79 +195,4 @@ class TestRearmed < MiniTest::Test
|
|
190
195
|
eql(str.in?('a real string'), false)
|
191
196
|
end
|
192
197
|
|
193
|
-
def test_minitest
|
194
|
-
str = 'first'
|
195
|
-
assert_changed "str" do
|
196
|
-
str = 'second'
|
197
|
-
end
|
198
|
-
|
199
|
-
str = 'first'
|
200
|
-
assert_changed ->{ str } do
|
201
|
-
str = 'second'
|
202
|
-
end
|
203
|
-
|
204
|
-
name = 'first'
|
205
|
-
assert_changed lambda{ name } do
|
206
|
-
name = 'second'
|
207
|
-
end
|
208
|
-
|
209
|
-
name = 'first'
|
210
|
-
assert_not_changed 'name' do
|
211
|
-
name = 'first'
|
212
|
-
end
|
213
|
-
|
214
|
-
name = 'first'
|
215
|
-
assert_not_changed ->{ name } do
|
216
|
-
name = 'first'
|
217
|
-
end
|
218
|
-
|
219
|
-
name = 'first'
|
220
|
-
assert_not_changed lambda{ name } do
|
221
|
-
name = 'first'
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def test_general_rails
|
226
|
-
# THE MOST IMPORTANT TESTS HERE WOULD BE dedupe, reset_auto_increment, reset_table
|
227
|
-
|
228
|
-
#Post.pluck_to_hash(:name, :category, :id)
|
229
|
-
#Post.pluck_to_struct(:name, :category, :id)
|
230
|
-
|
231
|
-
#Post.find_or_create(name: 'foo', content: 'bar') # use this instead of the super confusing first_or_create method
|
232
|
-
#Post.find_or_create!(name: 'foo', content: 'bar')
|
233
|
-
|
234
|
-
#Post.find_duplicates # return active record relation of all records that have duplicates
|
235
|
-
#Post.find_duplicates(:name) # find duplicates based on the name attribute
|
236
|
-
#Post.find_duplicates([:name, :category]) # find duplicates based on the name & category attribute
|
237
|
-
#Post.find_duplicates(name: 'A Specific Name')
|
238
|
-
|
239
|
-
#Post.reset_table # delete all records from table and reset autoincrement column (id), works with mysql/mariadb/postgresql/sqlite
|
240
|
-
## or with options
|
241
|
-
#Post.reset_table(delete_method: :destroy) # to ensure all callbacks are fired
|
242
|
-
|
243
|
-
#Post.reset_auto_increment # reset mysql/mariadb/postgresql/sqlite auto-increment column, if contains records then defaults to starting from next available number
|
244
|
-
## or with options
|
245
|
-
#Post.reset_auto_increment(value: 1, column: :id) # column option is only relevant for postgresql
|
246
|
-
|
247
|
-
#Post.find_in_relation_batches # this returns a relation instead of an array
|
248
|
-
#Post.find_relation_each # this returns a relation instead of an array
|
249
|
-
end
|
250
|
-
|
251
|
-
def test_rails_3
|
252
|
-
#my_hash.compact
|
253
|
-
#my_hash.compact!
|
254
|
-
#Post.all # Now returns AR relation
|
255
|
-
#Post.first.update_columns(a: 'foo', b: 'bar')
|
256
|
-
#Post.pluck(:name, :id) # adds multi column pluck support ex. => [['first', 1], ['second', 2], ['third', 3]]
|
257
|
-
end
|
258
|
-
|
259
|
-
def test_rails_4
|
260
|
-
#Post.where(name: 'foo').or.where(content: 'bar')
|
261
|
-
#Post.where(name: 'foo').or.my_custom_scope
|
262
|
-
#Post.where(name: 'foo').or(Post.where(content: 'bar'))
|
263
|
-
#Post.where(name: 'foo).or(content: 'bar')
|
264
|
-
|
265
|
-
#= link_to 'Delete', post_path(post), method: :delete, confirm: "Are you sure you want to delete this post?"
|
266
|
-
# returns to rails 3 behaviour of allowing confirm attribute as well as data-confirm
|
267
|
-
end
|
268
198
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rearmed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Weston Ganger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -63,7 +63,6 @@ files:
|
|
63
63
|
- LICENSE
|
64
64
|
- README.md
|
65
65
|
- Rakefile
|
66
|
-
- lib/generators/rearmed/setup_generator.rb
|
67
66
|
- lib/rearmed.rb
|
68
67
|
- lib/rearmed/apply_patches.rb
|
69
68
|
- lib/rearmed/default_enabled_patches.hash
|
@@ -73,11 +72,7 @@ files:
|
|
73
72
|
- lib/rearmed/monkey_patches/date.rb
|
74
73
|
- lib/rearmed/monkey_patches/enumerable.rb
|
75
74
|
- lib/rearmed/monkey_patches/hash.rb
|
76
|
-
- lib/rearmed/monkey_patches/minitest.rb
|
77
75
|
- lib/rearmed/monkey_patches/object.rb
|
78
|
-
- lib/rearmed/monkey_patches/rails.rb
|
79
|
-
- lib/rearmed/monkey_patches/rails_3.rb
|
80
|
-
- lib/rearmed/monkey_patches/rails_4.rb
|
81
76
|
- lib/rearmed/monkey_patches/string.rb
|
82
77
|
- lib/rearmed/version.rb
|
83
78
|
- test/tc_rearmed.rb
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'rails/generators'
|
2
|
-
|
3
|
-
module Rearmed
|
4
|
-
class SetupGenerator < Rails::Generators::Base
|
5
|
-
|
6
|
-
def setup
|
7
|
-
create_file "config/initializers/rearmed.rb", <<eos
|
8
|
-
Rearmed.enabled_patches = #{File.read(File.join(File.dirname(__FILE__), '../../rearmed/default_enabled_patches.hash'))}
|
9
|
-
|
10
|
-
require 'rearmed/apply_patches'
|
11
|
-
eos
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
if defined?(Minitest::Assertions)
|
2
|
-
|
3
|
-
enabled = Rearmed.enabled_patches[:minitest] == true
|
4
|
-
|
5
|
-
Minitest::Assertions.module_eval do
|
6
|
-
|
7
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :minitest, :assert_changed)
|
8
|
-
def assert_changed(expression, &block)
|
9
|
-
if expression.respond_to?(:call)
|
10
|
-
e = expression
|
11
|
-
else
|
12
|
-
e = lambda{ block.binding.eval(expression) }
|
13
|
-
end
|
14
|
-
old = e.call
|
15
|
-
block.call
|
16
|
-
refute_equal old, e.call
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :minitest, :assert_not_changed)
|
21
|
-
def assert_not_changed(expression, &block)
|
22
|
-
if expression.respond_to?(:call)
|
23
|
-
e = expression
|
24
|
-
else
|
25
|
-
e = lambda{ block.binding.eval(expression) }
|
26
|
-
end
|
27
|
-
old = e.call
|
28
|
-
block.call
|
29
|
-
assert_equal old, e.call
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
@@ -1,268 +0,0 @@
|
|
1
|
-
enabled = Rearmed.enabled_patches[:rails] == true
|
2
|
-
|
3
|
-
if defined?(ActiveRecord)
|
4
|
-
|
5
|
-
ActiveRecord::Base.class_eval do
|
6
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :newest)
|
7
|
-
def self.newest(*columns)
|
8
|
-
if columns.empty? || !columns.to_s.include?('created_at')
|
9
|
-
columns << 'created_at'
|
10
|
-
end
|
11
|
-
|
12
|
-
the_order = {}
|
13
|
-
columns.each do |x|
|
14
|
-
the_order[x.to_s] = :desc
|
15
|
-
end
|
16
|
-
self.order(the_order).limit(1).first
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :reset_table)
|
21
|
-
def self.reset_table(opts={})
|
22
|
-
if opts[:delete_method] && opts[:delete_method].to_sym == :destroy
|
23
|
-
if self.try(:paranoid?)
|
24
|
-
self.unscoped.each do |x|
|
25
|
-
if x.respond_to?(:really_destroy!)
|
26
|
-
x.really_destroy!
|
27
|
-
else
|
28
|
-
x.destroy!
|
29
|
-
end
|
30
|
-
end
|
31
|
-
else
|
32
|
-
self.unscoped.destroy_all
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
case self.connection.adapter_name.downcase.to_sym
|
37
|
-
when :mysql2
|
38
|
-
if !opts[:delete_method] || opts[:delete_method].to_sym != :destroy
|
39
|
-
if defined?(ActsAsParanoid) && self.try(:paranoid?)
|
40
|
-
self.unscoped.delete_all!
|
41
|
-
else
|
42
|
-
self.unscoped.delete_all
|
43
|
-
end
|
44
|
-
end
|
45
|
-
self.connection.execute("ALTER TABLE #{self.table_name} AUTO_INCREMENT = 1")
|
46
|
-
when :postgresql
|
47
|
-
self.connection.execute("TRUNCATE TABLE #{self.table_name} RESTART IDENTITY")
|
48
|
-
when :sqlite3
|
49
|
-
self.connection.execute("DELETE FROM #{self.table_name}")
|
50
|
-
self.connection.execute("DELETE FROM sqlite_sequence WHERE NAME='#{self.table_name}'")
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :reset_auto_increment)
|
56
|
-
def self.reset_auto_increment(opts={})
|
57
|
-
case self.connection.adapter_name.downcase.to_sym
|
58
|
-
when :mysql2
|
59
|
-
opts[:value] = 1 if opts[:value].blank?
|
60
|
-
self.connection.execute("ALTER TABLE #{self.table_name} AUTO_INCREMENT = #{opts[:value]}")
|
61
|
-
when :postgresql
|
62
|
-
opts[:value] = 1 if opts[:value].blank?
|
63
|
-
self.connection.execute("ALTER SEQUENCE #{self.table_name}_#{opts[:column].to_s || self.primary_key}_seq RESTART WITH #{opts[:value]}")
|
64
|
-
when :sqlite3
|
65
|
-
opts[:value] = 0 if opts[:value].blank?
|
66
|
-
self.connection.execute("UPDATE SQLITE_SEQUENCE SET SEQ=#{opts[:value]} WHERE NAME='#{self.table_name}'")
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :find_duplicates)
|
72
|
-
def self.find_duplicates(*args)
|
73
|
-
options = {}
|
74
|
-
|
75
|
-
unless args.empty?
|
76
|
-
if args.last.is_a?(Hash)
|
77
|
-
options = args.pop
|
78
|
-
end
|
79
|
-
|
80
|
-
unless args.empty?
|
81
|
-
if args.count == 1 && args.first.is_a?(Array)
|
82
|
-
args = args.first
|
83
|
-
end
|
84
|
-
|
85
|
-
options[:columns] = args
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
options[:columns] ||= self.column_names.reject{|x| [self.primary_key, :created_at, :updated_at, :deleted_at].include?(x)}
|
90
|
-
|
91
|
-
duplicates = self.select("#{options[:columns].join(', ')}, COUNT(*)").group(options[:columns]).having("COUNT(*) > 1")
|
92
|
-
|
93
|
-
if options[:delete]
|
94
|
-
if options[:delete] == true
|
95
|
-
options[:delete] = {keep: :first, delete_method: :destroy, soft_delete: true}
|
96
|
-
else
|
97
|
-
options[:delete][:delete_method] ||= :destroy
|
98
|
-
options[:delete][:keep] ||= :first
|
99
|
-
if options[:delete][:soft_delete] != false
|
100
|
-
options[:delete][:soft_delete] = true
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
if options[:delete][:keep] == :last
|
105
|
-
duplicates.reverse!
|
106
|
-
end
|
107
|
-
|
108
|
-
used = []
|
109
|
-
duplicates.reject! do |x|
|
110
|
-
attrs = x.attributes.slice(*options[:columns].collect(&:to_s))
|
111
|
-
|
112
|
-
if used.include?(attrs)
|
113
|
-
return false
|
114
|
-
else
|
115
|
-
used.push attrs
|
116
|
-
return true
|
117
|
-
end
|
118
|
-
end
|
119
|
-
used = nil
|
120
|
-
|
121
|
-
if options[:delete][:delete_method].to_sym == :delete
|
122
|
-
duplicates = self.where(id: duplicates.collect(&:id))
|
123
|
-
|
124
|
-
if x.respond_to?(:delete_all!)
|
125
|
-
duplicates.delete_all!
|
126
|
-
else
|
127
|
-
duplicates.delete_all
|
128
|
-
end
|
129
|
-
else
|
130
|
-
duplicates.each do |x|
|
131
|
-
if !options[:delete][:soft_delete] && x.respond_to?(:really_destroy!)
|
132
|
-
x.really_destroy!
|
133
|
-
else
|
134
|
-
x.destroy!
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
return nil
|
139
|
-
else
|
140
|
-
return duplicates
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :find_or_create)
|
146
|
-
def self.find_or_create(attrs={}, save_opts={})
|
147
|
-
unless self.where(attrs).limit(1).first
|
148
|
-
x = self.class.new(attrs)
|
149
|
-
x.save(save_opts)
|
150
|
-
return t
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def self.find_or_create!(attrs={}, save_opts={})
|
155
|
-
unless self.where(attrs).limit(1).first
|
156
|
-
x = self.class.new(attrs)
|
157
|
-
x.save!(save_opts)
|
158
|
-
return t
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :pluck_to_hash)
|
164
|
-
def self.pluck_to_hash(*keys)
|
165
|
-
hash_type = keys[-1].is_a?(Hash) ? keys.pop.fetch(:hash_type, HashWithIndifferentAccess) : HashWithIndifferentAccess
|
166
|
-
block_given = block_given?
|
167
|
-
keys, formatted_keys = format_keys(keys)
|
168
|
-
keys_one = keys.size == 1
|
169
|
-
|
170
|
-
pluck(*keys).map do |row|
|
171
|
-
value = hash_type[formatted_keys.zip(keys_one ? [row] : row)]
|
172
|
-
block_given ? yield(value) : value
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :pluck_to_struct)
|
178
|
-
def self.pluck_to_struct(*keys)
|
179
|
-
struct_type = keys[-1].is_a?(Hash) ? keys.pop.fetch(:struct_type, Struct) : Struct
|
180
|
-
block_given = block_given?
|
181
|
-
keys, formatted_keys = format_keys(keys)
|
182
|
-
keys_one = keys.size == 1
|
183
|
-
|
184
|
-
struct = struct_type.new(*formatted_keys)
|
185
|
-
pluck(*keys).map do |row|
|
186
|
-
value = keys_one ? struct.new(*[row]) : struct.new(*row)
|
187
|
-
block_given ? yield(value) : value
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
private
|
193
|
-
|
194
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :pluck_to_hash) || Rearmed.dig(Rearmed.enabled_patches, :rails, :pluck_to_struct)
|
195
|
-
def self.format_keys(keys)
|
196
|
-
if keys.blank?
|
197
|
-
[column_names, column_names]
|
198
|
-
else
|
199
|
-
[
|
200
|
-
keys,
|
201
|
-
keys.map do |k|
|
202
|
-
case k
|
203
|
-
when String
|
204
|
-
k.split(/\bas\b/i)[-1].strip.to_sym
|
205
|
-
when Symbol
|
206
|
-
k
|
207
|
-
end
|
208
|
-
end
|
209
|
-
]
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
ActiveRecord::Batches.module_eval do
|
216
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :find_in_relation_batches)
|
217
|
-
def find_in_relation_batches(options = {})
|
218
|
-
options.assert_valid_keys(:start, :batch_size)
|
219
|
-
|
220
|
-
relation = self
|
221
|
-
start = options[:start]
|
222
|
-
batch_size = options[:batch_size] || 1000
|
223
|
-
|
224
|
-
unless block_given?
|
225
|
-
return to_enum(:find_in_relation_batches, options) do
|
226
|
-
total = start ? where(table[primary_key].gteq(start)).size : size
|
227
|
-
(total - 1).div(batch_size) + 1
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
if logger && (arel.orders.present? || arel.taken.present?)
|
232
|
-
logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
|
233
|
-
end
|
234
|
-
|
235
|
-
relation = relation.reorder(batch_order).limit(batch_size)
|
236
|
-
#records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
|
237
|
-
records = start ? relation.where(table[primary_key].gteq(start)) : relation
|
238
|
-
|
239
|
-
while records.any?
|
240
|
-
records_size = records.size
|
241
|
-
primary_key_offset = records.last.id
|
242
|
-
raise ActiveRecordError, "Primary key not included in the custom select clause" unless primary_key_offset
|
243
|
-
|
244
|
-
yield records
|
245
|
-
|
246
|
-
break if records_size < batch_size
|
247
|
-
|
248
|
-
records = relation.where(table[primary_key].gt(primary_key_offset))#.to_a
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :find_relation_each)
|
254
|
-
def find_relation_each(options = {})
|
255
|
-
if block_given?
|
256
|
-
find_in_relation_batches(options) do |records|
|
257
|
-
records.each { |record| yield record }
|
258
|
-
end
|
259
|
-
else
|
260
|
-
enum_for :find_relation_each, options do
|
261
|
-
options[:start] ? where(table[primary_key].gteq(options[:start])).size : size
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
enabled = Rearmed.enabled_patches[:rails_3] == true
|
2
|
-
|
3
|
-
if defined?(ActiveRecord) && ActiveRecord::VERSION::MAJOR < 4
|
4
|
-
|
5
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :all)
|
6
|
-
ActiveRecord::FinderMethods.module_eval do
|
7
|
-
def all(*args)
|
8
|
-
args.any? ? apply_finder_options(args.first) : self
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :update_columns)
|
14
|
-
ActiveRecord::Persistence::ClassMethods.module_eval do
|
15
|
-
def update_columns(attributes)
|
16
|
-
raise ActiveRecordError, "cannot update a new record" if new_record?
|
17
|
-
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
18
|
-
|
19
|
-
attributes.each_key do |key|
|
20
|
-
raise ActiveRecordError, "#{key.to_s} is marked as readonly" if self.class.readonly_attributes.include?(key.to_s)
|
21
|
-
end
|
22
|
-
|
23
|
-
updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)
|
24
|
-
|
25
|
-
attributes.each do |k, v|
|
26
|
-
raw_write_attribute(k, v)
|
27
|
-
end
|
28
|
-
|
29
|
-
updated_count == 1
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_3, :pluck)
|
35
|
-
ActiveRecord::Relation.class_eval do
|
36
|
-
def pluck(*args)
|
37
|
-
args.map! do |column_name|
|
38
|
-
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
|
39
|
-
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
|
40
|
-
else
|
41
|
-
column_name.to_s
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
relation = clone
|
46
|
-
relation.select_values = args
|
47
|
-
klass.connection.select_all(relation.arel).map! do |attributes|
|
48
|
-
initialized_attributes = klass.initialize_attributes(attributes)
|
49
|
-
attributes.map do |key, attr|
|
50
|
-
klass.type_cast_attribute(key, initialized_attributes)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
@@ -1,143 +0,0 @@
|
|
1
|
-
enabled = Rearmed.enabled_patches[:rails_4] == true
|
2
|
-
|
3
|
-
if defined?(ActionView) && enabled || Rearmed.dig(Rearmed.enabled_patches, :rails_4, :link_to_confirm)
|
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)
|
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 ActiveRecordError, "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)
|
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)
|
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
|