rearmed 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
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