rearmed 1.2.1 → 1.3.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: d1c1c9a931a133791cfbdacdbfd5ccb01f50234d
4
- data.tar.gz: 6daedcedcc902bfed66cad975fbcf99f34724163
3
+ metadata.gz: 1a547fa7cd7259d77eee0a4707cd1cf9589e9aa2
4
+ data.tar.gz: a0be2f3e5e61f6c6ffb8da8213bfd9dd7b767b6d
5
5
  SHA512:
6
- metadata.gz: 00253c513c5b1e4ba17485a1c7e72a2c5070e3e80121d8a612f5c8ebe10f06d04bff262bd117856a9fcffa0f1254e9fc9de5b50074bc61b126333e8a9be42624
7
- data.tar.gz: c52b3d027600904d10d8ba89b3d9cb587ab6688c2b0c19a72fdb8b3d4766d177fc0d26d061283240ff86c277a515011bbb8c45c14a1409534492fb18d8aee341
6
+ metadata.gz: f4fff0c4782edd10fee028e471469fa73ab5f8a0b8c0fa6a91f6debe23a9451e2afe7e45fe09c34ef9c6ad3b38686d5cb5f9fee199108706c6f86766279f429b
7
+ data.tar.gz: a6ba345629c2076c05c8fd219eddc4c4fe63772ebd683d81f967328759e1a88c1f862b636a27330f34df8dd0c5086901f74d0956ec68a7ce15cb8d98c9697183
@@ -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, Minitest & Rails (optional)
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
- 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.
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
- 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. If your not using Rails then just copy config this into your file and start from there.
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
- ### Array Methods
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
- ### Enumerable Methods (Array, Hash, etc.)
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
- ### Date
93
+ ## Date
114
94
  ```ruby
115
95
  Date.now
116
96
  ```
117
97
 
118
- ### Hash Methods
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.only(hash, :foo, :bar)
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
- ### Object
122
+ ## Object
140
123
  ```ruby
141
124
  my_var.not_nil?
142
125
 
143
- # Only for non-Rails environments, as Rails already has this method
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
- ### String
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
- find_duplicates: false,
39
- find_in_relation_batches: false,
40
- find_or_create: false,
41
- find_relation_each: false,
42
- newest: false,
43
- pluck_to_hash: false,
44
- pluck_to_struct: false,
45
- reset_auto_increment: false,
46
- reset_table: false
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,
@@ -35,7 +35,7 @@ module Rearmed
35
35
  return current_val
36
36
  end
37
37
 
38
- def self.join(hash, delimiter=', ', &block)
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.only(hash, *keys)
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 RUBY_VERSION.to_f < 2.3 && array_enabled || Rearmed.dig(Rearmed.enabled_patches, :array, :dig)
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
- allowed = defined?(ActiveSupport) ? (ActiveSupport::VERSION::MAJOR > 3) : true
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.select{|_, value| !value.nil?}
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 RUBY_VERSION.to_f < 2.3 && hash_enabled || Rearmed.dig(Rearmed.enabled_patches, :hash, :dig)
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.join(self, delimiter, &block)
23
+ Rearmed.hash_join(self, delimiter, &block)
25
24
  else
26
- Rearmed.join(self, delimiter)
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.only(self, *keys)
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
- Struct.new(*keys).new(*values)
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 !defined?(ActiveSupport) && (object_enabled || Rearmed.dig(Rearmed.enabled_patches, :object, :in))
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]
@@ -1,3 +1,3 @@
1
1
  module Rearmed
2
- VERSION = "1.2.1"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -58,10 +58,9 @@ class TestRearmed < MiniTest::Test
58
58
  eql(str.to_bool, false)
59
59
 
60
60
  str = 'not true'
61
- eql(str.to_bool, nil)
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
- eql(array.dig(0, :foo, 2), nil)
101
+ assert_nil(array.dig(0, :foo, 2))
103
102
 
104
103
  eql(Rearmed.dig(array, 1, :test), 'thing')
105
- eql(Rearmed.dig(array, 1, :bar), nil)
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.only(hash, :foo, :bar), {foo: 'foo', bar: 'bar'})
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.join(hash), "foo: bar, bar: foo")
153
- eql(Rearmed.join(hash, '___'), "foo: bar___bar: foo")
154
- eql(Rearmed.join(hash){|k,v| v}, "bar, foo")
155
- eql(Rearmed.join(hash, '___'){|k,v| v}, "bar___foo")
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.2.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-01-24 00:00:00.000000000 Z
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