rearmed 1.1.1 → 1.2.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: dbe46727111f0be87f94d4723c3d197f16726f41
4
- data.tar.gz: 91214ba423916acb587ad450806921c2cf3df20b
3
+ metadata.gz: 270b7582528a427dfcd54ea2cbe616af8bc67717
4
+ data.tar.gz: e97b0352883c108aa366ec3078bf188349e1b907
5
5
  SHA512:
6
- metadata.gz: 7f8fb8b6fe0e0282856f7d54ea4a46391eba309ef3be1019dbf78fc448c2f8f26c9d8af357a1af80fcff1a84d3f9c8c3bb1ebed3d238658bc04fb9c3868d560f
7
- data.tar.gz: e7079c6bbe93c6b46210f334d9e33b318db215edbc9fed5d36a04bd34186a5e8fd1ef1621078898a0f66e843074c78ed4e671794b142205b17d81b70bc836b87
6
+ metadata.gz: f4785d8f2332220c02dbe2d904ef328ff4554b98f6711c5e095a071beb52c6000ae540228c53f732beb9987e435c7d8c5820fb317d959fa4815b2f6e8247cf00
7
+ data.tar.gz: 9f77a7b3b1e35f8027b00d676076e7e90ce33b88e34efdaa82b927c57b1caaa5e69bb8aa108b8b29c9f220911c45879d29f0dfa6d6df29d6d151cca0efec22dc
data/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  CHANGELOG
2
2
  ---------
3
3
 
4
+ -
5
+ - **1.2.0 - September 3, 2016**
6
+ - Add Minitest patches `assert_changed` & `assert_not_changed`
7
+ - Remove `dedupe` in favor of new `find_duplicates`
8
+ - Add ActiveRecord `newest`
9
+ - **1.1.1 - August 20, 2016**
10
+ - Add Array `not_empty?`
4
11
  - **1.1.0 - July 8, 2016**
5
12
  - Add ActiveRecord `find_or_create`, `reset_table`, `reset_auto_increment`, `depupe`
6
13
  - Add `starts_with?`, `begins_with?`, `ends_with?` aliases
data/README.md CHANGED
@@ -1,7 +1,7 @@
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, & Rails
4
+ A collection of helpful methods and monkey patches for Objects, Strings, Enumerables, Arrays, Hash, Dates, Minitest & Rails
5
5
 
6
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
7
 
@@ -32,9 +32,10 @@ Rearmed.enabled_patches = {
32
32
  pluck_to_hash: false,
33
33
  pluck_to_struct: false,
34
34
  find_or_create: false,
35
+ find_duplicates: false,
36
+ newest: false,
35
37
  reset_table: false,
36
38
  reset_auto_increment: false,
37
- dedupe: false,
38
39
  find_relation_each: false,
39
40
  find_in_relation_batches: false,
40
41
  },
@@ -66,6 +67,10 @@ Rearmed.enabled_patches = {
66
67
  },
67
68
  date: {
68
69
  now: false
70
+ },
71
+ minitest: {
72
+ assert_changed: false,
73
+ assert_not_changed: false
69
74
  }
70
75
  }
71
76
 
@@ -157,6 +162,19 @@ Post.pluck_to_struct(:name, :category, :id)
157
162
  Post.find_or_create(name: 'foo', content: 'bar') # use this instead of the super confusing first_or_create method
158
163
  Post.find_or_create!(name: 'foo', content: 'bar')
159
164
 
165
+ 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
166
+ Post.find_duplicates(:name) # find duplicates based on the name attribute
167
+ Post.find_duplicates(:name, :category) # find duplicates based on the name & category attribute
168
+ Post.find_duplicates(self.column_names.reject{|x| ['id','created_at','updated_at','deleted_at'].include?(x)})
169
+
170
+ # 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.
171
+ Post.find_duplicates(:name, :category, delete: true)
172
+ Post.find_duplicates(:name, :category, delete: {keep: :first, delete_method: :destroy, soft_delete: true}) # these are the default settings for delete: true
173
+
174
+ Post.newest # get the newest post, by default ordered by :created_at
175
+ Post.newest(:updated_at) # different sort order
176
+ Post.newest(:published_at, :created_at) # multiple columns to sort on
177
+
160
178
  Post.reset_table # delete all records from table and reset autoincrement column (id), works with mysql/mariadb/postgresql/sqlite
161
179
  # or with options
162
180
  Post.reset_table(delete_method: :destroy) # to ensure all callbacks are fired
@@ -165,13 +183,6 @@ Post.reset_auto_increment # reset mysql/mariadb/postgresql/sqlite auto-increment
165
183
  # or with options
166
184
  Post.reset_auto_increment(value: 1, column: :id) # column option is only relevant for postgresql
167
185
 
168
- Post.dedupe # remove all duplicate records, defaults to all of the models column_names except timestamps
169
- # or with options
170
- Post.dedupe(delete_method: :destroy) # to ensure all callbacks are fired
171
- Post.dedupe(columns: [:name, :content, :category_id]
172
- Post.dedupe(skip_timestamps: false) # skip timestamps defaults to true (created_at, updated_at, deleted_at)
173
- Post.dedupe(keep: :last) # Keep the last duplicate instead of the first duplicate by default
174
-
175
186
  Post.find_in_relation_batches # this returns a relation instead of an array
176
187
  Post.find_relation_each # this returns a relation instead of an array
177
188
  ```
@@ -197,6 +208,21 @@ my_hash.compact # See Hash methods above
197
208
  my_hash.compact!
198
209
  ```
199
210
 
211
+ ### Minitest Method
212
+ ```ruby
213
+ assert_changed 'user.name' do
214
+ user.name = "Bob"
215
+ end
216
+
217
+ assert_not_changed -> { user.name } do
218
+ user.update(user_params)
219
+ end
220
+
221
+ assert_not_changed lambda{ user.name } do
222
+ user.update(user_params)
223
+ end
224
+ ```
225
+
200
226
  # Contributing / Todo
201
227
  If you want to request a method please raise an issue and we can discuss the implementation.
202
228
 
@@ -204,6 +230,7 @@ If you want to contribute here are a couple of things you could do:
204
230
 
205
231
  - Add Tests for Rails methods
206
232
  - Get the `natural_sort` method to accept a block
233
+ - Get the `assert_changed` and `assert_not_changed` method to accept a String with the variable name similar to Rails ``
207
234
 
208
235
 
209
236
  # Credits
@@ -19,9 +19,10 @@ Rearmed.enabled_patches = {
19
19
  pluck_to_hash: false,
20
20
  pluck_to_struct: false,
21
21
  find_or_create: false,
22
+ find_duplicates: false,
23
+ newest: false,
22
24
  reset_table: false,
23
25
  reset_auto_increment: false,
24
- dedupe: false,
25
26
  find_relation_each: false,
26
27
  find_in_relation_batches: false,
27
28
  },
@@ -53,6 +54,10 @@ Rearmed.enabled_patches = {
53
54
  },
54
55
  date: {
55
56
  now: false
57
+ },
58
+ minitest: {
59
+ assert_changed: false,
60
+ assert_not_changed: false
56
61
  }
57
62
  }
58
63
 
data/lib/rearmed.rb CHANGED
@@ -3,28 +3,40 @@ module Rearmed
3
3
  @enabled_patches = {
4
4
  rails_4: {
5
5
  or: false,
6
- link_to_confirm: false,
7
- find_relation_each: false,
8
- find_in_relation_batches: false
6
+ link_to_confirm: false
9
7
  },
10
8
  rails_3: {
11
- hash_compact: false,
12
9
  pluck: false,
13
10
  update_columns: false,
14
11
  all: false
15
12
  },
13
+ rails: {
14
+ pluck_to_hash: false,
15
+ pluck_to_struct: false,
16
+ find_or_create: false,
17
+ find_duplicates: false,
18
+ reset_table: false,
19
+ reset_auto_increment: false,
20
+ find_relation_each: false,
21
+ find_in_relation_batches: false,
22
+ },
16
23
  string: {
17
- to_bool: false,
18
24
  valid_integer: false,
19
- valid_float: false
25
+ valid_float: false,
26
+ to_bool: false,
27
+ starts_with: false,
28
+ begins_with: false,
29
+ ends_with: false
20
30
  },
21
31
  hash: {
22
32
  only: false,
23
- dig: false
33
+ dig: false,
34
+ compact: false
24
35
  },
25
36
  array: {
26
37
  dig: false,
27
- delete_first: false
38
+ delete_first: false,
39
+ not_empty: false
28
40
  },
29
41
  enumerable: {
30
42
  natural_sort: false,
@@ -36,6 +48,10 @@ module Rearmed
36
48
  },
37
49
  date: {
38
50
  now: false
51
+ },
52
+ minitest: {
53
+ assert_changed: false,
54
+ assert_not_changed: false
39
55
  }
40
56
  }
41
57
 
@@ -7,3 +7,4 @@ require 'rearmed/monkey_patches/rails'
7
7
  require 'rearmed/monkey_patches/rails_3'
8
8
  require 'rearmed/monkey_patches/rails_4'
9
9
  require 'rearmed/monkey_patches/date'
10
+ require 'rearmed/monkey_patches/minitest'
@@ -0,0 +1,35 @@
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
@@ -3,6 +3,20 @@ enabled = Rearmed.enabled_patches[:rails] == true
3
3
  if defined?(ActiveRecord)
4
4
 
5
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
+
6
20
  if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :reset_table)
7
21
  def self.reset_table(opts={})
8
22
  if opts[:delete_method] && opts[:delete_method].to_sym == :destroy
@@ -46,7 +60,7 @@ if defined?(ActiveRecord)
46
60
  self.connection.execute("ALTER TABLE #{self.table_name} AUTO_INCREMENT = #{opts[:value]}")
47
61
  when :postgresql
48
62
  opts[:value] = 1 if opts[:value].blank?
49
- self.connection.execute("ALTER SEQUENCE #{self.table_name}_#{opts[:column].to_s || 'id'}_seq RESTART WITH #{opts[:value]}")
63
+ self.connection.execute("ALTER SEQUENCE #{self.table_name}_#{opts[:column].to_s || self.primary_key}_seq RESTART WITH #{opts[:value]}")
50
64
  when :sqlite3
51
65
  opts[:value] = 0 if opts[:value].blank?
52
66
  self.connection.execute("UPDATE SQLITE_SEQUENCE SET SEQ=#{opts[:value]} WHERE NAME='#{self.table_name}'")
@@ -54,33 +68,59 @@ if defined?(ActiveRecord)
54
68
  end
55
69
  end
56
70
 
57
- if enabled || Rearmed.dig(Rearmed.enabled_patches, :rails, :dedupe)
58
- def self.dedupe(opts={})
59
- if !opts[:columns]
60
- opts[:columns] = self.column_names.reject{|x| x == 'id'}
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
61
87
  end
62
88
 
63
- if opts[:skip_timestamps] != false
64
- opts[:columns].reject!{|x| ['created_at','updated_at','deleted_at'].include?(x)}
65
- end
89
+ options[:columns] ||= self.column_names.reject{|x| [self.primary_key, :created_at, :updated_at, :deleted_at].include?(x)}
90
+
91
+ ids = self.select("MIN(#{self.primary_key}) as #{self.primary_key}").group(options[:columns]).pluck(self.primary_key)
66
92
 
67
- self.all.group_by{|model| opts[:columns].map{|x| model[x]}}.values.each do |duplicates|
68
- (opts[:keep] && opts[:keep].to_sym == :last) ? duplicates.pop : duplicates.shift
69
- if opts[:delete_method] && opts[:delete_method].to_sym == :destroy
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
+ duplicates = self.where.not(self.primary_key => ids)
105
+
106
+ if options[:delete][:delete_method].to_sym == :delete
107
+ if x.respond_to?(:delete_all!)
108
+ duplicates.delete_all!
109
+ else
110
+ duplicates.delete_all
111
+ end
112
+ else
70
113
  duplicates.each do |x|
71
- if x.respond_to?(:really_destroy!)
114
+ if !options[:delete][:soft_delete] && x.respond_to?(:really_destroy!)
72
115
  x.really_destroy!
73
116
  else
74
117
  x.destroy!
75
118
  end
76
119
  end
77
- else
78
- if defined?(ActsAsParanoid) && self.try(:paranoid?)
79
- self.unscoped.where(id: duplicates.collect(&:id)).delete_all!
80
- else
81
- self.unscoped.where(id: duplicates.collect(&:id)).delete_all
82
- end
83
120
  end
121
+ return nil
122
+ else
123
+ return self.where.not(self.primary_key => ids)
84
124
  end
85
125
  end
86
126
  end
@@ -1,3 +1,3 @@
1
1
  module Rearmed
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
data/test/tc_rearmed.rb CHANGED
@@ -25,7 +25,8 @@ class TestRearmed < MiniTest::Test
25
25
  enumerable: true,
26
26
  rails_3: true,
27
27
  rails_4: true,
28
- rails: true
28
+ rails: true,
29
+ minitest: true
29
30
  }
30
31
  require 'rearmed/apply_patches'
31
32
  end
@@ -174,27 +175,60 @@ class TestRearmed < MiniTest::Test
174
175
  eql(str.in?('a real string'), false)
175
176
  end
176
177
 
178
+ def test_minitest
179
+ str = 'first'
180
+ assert_changed "str" do
181
+ str = 'second'
182
+ end
183
+
184
+ str = 'first'
185
+ assert_changed ->{ str } do
186
+ str = 'second'
187
+ end
188
+
189
+ name = 'first'
190
+ assert_changed lambda{ name } do
191
+ name = 'second'
192
+ end
193
+
194
+ name = 'first'
195
+ assert_not_changed 'name' do
196
+ name = 'first'
197
+ end
198
+
199
+ name = 'first'
200
+ assert_not_changed ->{ name } do
201
+ name = 'first'
202
+ end
203
+
204
+ name = 'first'
205
+ assert_not_changed lambda{ name } do
206
+ name = 'first'
207
+ end
208
+ end
209
+
177
210
  def test_general_rails
178
211
  # THE MOST IMPORTANT TESTS HERE WOULD BE dedupe, reset_auto_increment, reset_table
179
212
 
180
- #Post.reset_table # delete all records from table and reset autoincrement column (id), works with mysql/mariadb/postgresql/sqlite
181
- # or with options
182
- #Post.reset_table(delete_method: :destroy) # use destroy_all to ensure all callbacks are fired
183
-
184
- #Post.reset_auto_increment # reset mysql/mariadb/postgresql/sqlite auto-increment column
185
- # or with options
186
- #Post.reset_auto_increment(value: 1, column: :id)
187
-
188
- #Post.dedupe # remove all duplicate records, defaults to the models column_names list
189
- # or with options
190
- #Post.dedupe(columns: [:name, :content, :category_id])
191
- #Post.dedupe(skip_timestamps: true)
192
213
  #Post.pluck_to_hash(:name, :category, :id)
193
214
  #Post.pluck_to_struct(:name, :category, :id)
194
215
 
195
216
  #Post.find_or_create(name: 'foo', content: 'bar') # use this instead of the super confusing first_or_create method
196
217
  #Post.find_or_create!(name: 'foo', content: 'bar')
197
218
 
219
+ #Post.find_duplicates # return active record relation of all records that have duplicates
220
+ #Post.find_duplicates(:name) # find duplicates based on the name attribute
221
+ #Post.find_duplicates([:name, :category]) # find duplicates based on the name & category attribute
222
+ #Post.find_duplicates(name: 'A Specific Name')
223
+
224
+ #Post.reset_table # delete all records from table and reset autoincrement column (id), works with mysql/mariadb/postgresql/sqlite
225
+ ## or with options
226
+ #Post.reset_table(delete_method: :destroy) # to ensure all callbacks are fired
227
+
228
+ #Post.reset_auto_increment # reset mysql/mariadb/postgresql/sqlite auto-increment column, if contains records then defaults to starting from next available number
229
+ ## or with options
230
+ #Post.reset_auto_increment(value: 1, column: :id) # column option is only relevant for postgresql
231
+
198
232
  #Post.find_in_relation_batches # this returns a relation instead of an array
199
233
  #Post.find_relation_each # this returns a relation instead of an array
200
234
  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.1.1
4
+ version: 1.2.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: 2016-08-20 00:00:00.000000000 Z
11
+ date: 2016-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  description: A collection of helpful methods and monkey patches for Objects, Strings,
56
- Enumerables, Arrays, Hash, Dates, & Rails
56
+ Enumerables, Arrays, Hash, Dates, Minitest & Rails
57
57
  email: westonganger@gmail.com
58
58
  executables: []
59
59
  extensions: []
@@ -70,6 +70,7 @@ files:
70
70
  - lib/rearmed/monkey_patches/date.rb
71
71
  - lib/rearmed/monkey_patches/enumerable.rb
72
72
  - lib/rearmed/monkey_patches/hash.rb
73
+ - lib/rearmed/monkey_patches/minitest.rb
73
74
  - lib/rearmed/monkey_patches/object.rb
74
75
  - lib/rearmed/monkey_patches/rails.rb
75
76
  - lib/rearmed/monkey_patches/rails_3.rb
@@ -100,6 +101,6 @@ rubygems_version: 2.5.1
100
101
  signing_key:
101
102
  specification_version: 4
102
103
  summary: A collection of helpful methods and monkey patches for Objects, Strings,
103
- Enumerables, Arrays, Hash, Dates, & Rails
104
+ Enumerables, Arrays, Hash, Dates, Minitest & Rails
104
105
  test_files:
105
106
  - test/tc_rearmed.rb