affairs_of_state 0.7.0 → 0.7.1

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
  SHA256:
3
- metadata.gz: 73f6fed4bcc0422024de20521810e21f4d9a77411382af6d6b8f52c79f941ca7
4
- data.tar.gz: b128a4dcea99c0c3e192792ffea7a6a6b670f58994c26bd2c8d808360fd620bf
3
+ metadata.gz: 393e826c50c889d987390c00c48332b5f25b36dacc8977a4b6ae872b031507c0
4
+ data.tar.gz: 268729f4f4e5d03616028ae9ad663e9333ec77be659c1eb17ff4ba78f9ea44f1
5
5
  SHA512:
6
- metadata.gz: 8fe6d2bf961248735b23fa41afaa2ebe8712a9ea55896537c6dd66efcabe1426491635e8fa3be707bbb068756a7fc3f726893cb6cefc36a61b36f6785a1c3f45
7
- data.tar.gz: b5df8b2a439fead18dc1e79340141137b307ecb1024d7e82884f17312f9231f3e26d680e5bd31309da2447e183ee27b8a7d5ae1470e89929172c5422dd806eeb
6
+ metadata.gz: b28c839c99db9cf1a7560766f46bda687825c23e6d17c2f20b1246d239990f26a450e5a9350c10f1ea191678b929ecf88c0a389be7620d13f37e26d3d02525eb
7
+ data.tar.gz: 88a2b5f1cefe5ac0017eeaa9b2c2d480895b51f31497adf049a8ce54dbd3966f3c9e8f472d1b300e9d650c644ca1cb3b67063ddcbf7067e914e21c42d96a05f6
data/README.md CHANGED
@@ -38,6 +38,12 @@ If you'd like to use another column, lets say `state`, pass it in as a configura
38
38
  affairs_of_state :active, :inactive, column: :state
39
39
  ```
40
40
 
41
+ You can scope the helper and scope methods by a prefix:
42
+
43
+ ```ruby
44
+ affairs_of_state :active, :inactive, prefix: :admin
45
+ ```
46
+
41
47
  You can also turn off validation:
42
48
 
43
49
  ```ruby
@@ -72,6 +78,12 @@ widget = Widget.first
72
78
  widget.cancelled! if widget.active?
73
79
  ```
74
80
 
81
+ These methods are scoped by the prefix if one is set:
82
+ ```ruby
83
+ widget = Widget.first
84
+ widget.admin_cancelled! if widget.admin_active?
85
+ ```
86
+
75
87
  You can also access all your statuses on the model. If only one is defined it is default, otherwise the column name needs to be passed in:
76
88
 
77
89
  ```ruby
@@ -79,12 +91,16 @@ Widget.statuses # -> ["active", "cancelled"]
79
91
  Widget.statuses(:status) # -> ["active", "cancelled"]
80
92
  ```
81
93
 
82
- It also provides scopes automagically:
94
+ It also provides scopes automagically, scoped by prefix if one is set:
83
95
 
84
96
  ```ruby
85
97
  Widget.active
86
98
  Widget.cancelled
87
99
  ```
100
+ ```ruby
101
+ Widget.admin_active
102
+ Widget.admin_cancelled
103
+ ```
88
104
 
89
105
  For select inputs in forms there is a convenience method that returns all states in the format expected by `options_for_select`. Again if only one is defined on the model it returns as default, if multiple are defined the column name needs to be passed in:
90
106
 
@@ -4,10 +4,11 @@ module AffairsOfState
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  class_methods do
7
- def affairs_of_state(*statuses, column: :status, allow_blank: false, scopes: true, if: nil)
7
+ def affairs_of_state(*statuses, column: :status, allow_blank: false, scopes: true, if: nil, prefix: nil)
8
8
  # config object that defines behaviour
9
9
  config = AffairsOfState::Config.new(
10
10
  statuses: statuses,
11
+ prefix: prefix,
11
12
  column: column,
12
13
  allow_blank: !!allow_blank,
13
14
  scopes: scopes,
@@ -16,31 +17,32 @@ module AffairsOfState
16
17
 
17
18
  # check for conflicts with existing calls
18
19
  raise ArgumentError, "Affairs of State: #{ self } has already been called on `#{ config.column }`" if affairs_of_state_configs[config.column]
19
- overlapping_statuses = affairs_of_state_configs.values.map(&:statuses) & config.statuses
20
+ statuses_and_methods = affairs_of_state_configs.values.map(&:methods_for_statuses).map { |m| m.map{ |(k, v)| [k, v] } }.flatten
21
+ overlapping_statuses = statuses_and_methods & config.methods_for_statuses.map{ |k, v| [k, v] }.flatten
20
22
  raise ArgumentError, "Affairs of State: #{ self } already has a status #{ overlapping_statuses }" if overlapping_statuses.any?
21
23
 
22
24
  # status methods
23
- config.statuses.each do |status|
24
- define_method("#{ status }?") do
25
+ config.methods_for_statuses.each do |status, method_name|
26
+ define_method("#{ method_name }?") do
25
27
  self.send(config.column) == status
26
28
  end
27
29
 
28
- define_method("#{ status }!") do
30
+ define_method("#{ method_name }!") do
29
31
  self.send("#{ config.column }=", status)
30
32
  self.save
31
33
  end
32
34
  end
33
35
 
34
- # column validation
35
- validates(config.column, inclusion: { in: config.statuses, allow_blank: config.allow_blank }, if: config.if)
36
-
37
36
  # scopes
38
37
  if config.scopes
39
- config.statuses.each do |status|
40
- self.scope(status.to_sym, -> { where(config.column => status) })
38
+ config.methods_for_statuses.each do |status, method_name|
39
+ self.scope(method_name.to_sym, -> { where(config.column => status) })
41
40
  end
42
41
  end
43
42
 
43
+ # column validation
44
+ validates(config.column, inclusion: { in: config.statuses, allow_blank: config.allow_blank }, if: config.if)
45
+
44
46
  # cache the config on the object
45
47
  affairs_of_state_configs[config.column] = config
46
48
 
@@ -1,16 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
  module AffairsOfState
3
3
  class Config
4
- attr_reader :statuses, :column, :allow_blank, :scopes, :if
4
+ attr_reader :statuses, :column, :allow_blank, :scopes, :if, :methods_for_statuses
5
5
 
6
6
  DISALLOWED_STATUSES = [ "new" ].freeze
7
7
 
8
- def initialize(statuses:, column:, allow_blank:, scopes:, if:)
8
+ def initialize(statuses:, column:, allow_blank:, scopes:, if:, prefix:)
9
9
  @column = column
10
10
  @allow_blank = !!allow_blank
11
11
  @scopes = !!scopes
12
12
  @if = binding.local_variable_get(:if)
13
+ @prefix = prefix.presence
13
14
  @statuses = statuses.flatten.map(&:to_s)
15
+ @methods_for_statuses = @statuses.to_h do |s|
16
+ if @prefix
17
+ [s.to_s, "#{ prefix }_#{ s }"]
18
+ else
19
+ [s.to_s, s.to_s]
20
+ end
21
+ end
14
22
  @statuses.each do |status|
15
23
  raise ArgumentError.new("Affairs of State: '#{ status }' is not a valid status") if DISALLOWED_STATUSES.include?(status)
16
24
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module AffairsOfState
3
- VERSION = "0.7.0"
3
+ VERSION = "0.7.1"
4
4
  end
@@ -215,7 +215,7 @@ describe AffairsOfState do
215
215
 
216
216
  it "raises if called twice on the same column" do
217
217
  expect {
218
- class Pie < ActiveRecord::Base
218
+ class Pie10 < ActiveRecord::Base
219
219
  self.table_name = "pies"
220
220
 
221
221
  affairs_of_state :active, :inactive
@@ -226,7 +226,7 @@ describe AffairsOfState do
226
226
 
227
227
  it "raises if called twice with the same status in both" do
228
228
  expect {
229
- class Pie < ActiveRecord::Base
229
+ class Pie11 < ActiveRecord::Base
230
230
  self.table_name = "pies"
231
231
 
232
232
  affairs_of_state :active, :inactive
@@ -235,6 +235,17 @@ describe AffairsOfState do
235
235
  }.to raise_error(ArgumentError)
236
236
  end
237
237
 
238
+ it "raises if collision between prefixes" do
239
+ expect {
240
+ class Pie12 < ActiveRecord::Base
241
+ self.table_name = "pies"
242
+
243
+ affairs_of_state :admin_active, :admin_inactive
244
+ affairs_of_state :dormant, :active, column: :super_status, prefix: :admin
245
+ end
246
+ }.to raise_error(ArgumentError)
247
+ end
248
+
238
249
  it "raises if statuses is called with no argument" do
239
250
  expect {
240
251
  subject.statuses
@@ -257,4 +268,36 @@ describe AffairsOfState do
257
268
  expect(subject.statuses_for_select("super_status")).to eq([["Moderated", "moderated"], ["Unmoderated", "unmoderated"]])
258
269
  end
259
270
  end
271
+
272
+ describe "multiple invocations with prefix" do
273
+ class Pie13 < ActiveRecord::Base
274
+ self.table_name = "pies"
275
+
276
+ affairs_of_state :active, :inactive
277
+ affairs_of_state :moderated, :unmoderated, column: :super_status
278
+ affairs_of_state :positive, :mixed, :negative, column: :sentiment, prefix: :sentiment
279
+ end
280
+
281
+ subject { Pie13 }
282
+
283
+ it "returns the statuses" do
284
+ expect(subject.statuses(:sentiment)).to eq([ "positive", "mixed", "negative" ])
285
+ end
286
+
287
+ it "adds the setter and getter methods with the prefix" do
288
+ p = subject.new
289
+ expect(p).to_not be_sentiment_positive
290
+ expect(p).to_not be_sentiment_mixed
291
+ expect(p).to_not be_sentiment_negative
292
+ p.sentiment_mixed!
293
+ expect(p).to be_sentiment_mixed
294
+ end
295
+
296
+ it "adds the scopes with the prefix" do
297
+ p = subject.create! sentiment: "positive", status: "active", super_status: "unmoderated"
298
+ subject.create! sentiment: "mixed", status: "active", super_status: "unmoderated"
299
+ subject.create! sentiment: "negative", status: "active", super_status: "unmoderated"
300
+ expect(subject.sentiment_positive).to eq([p])
301
+ end
302
+ end
260
303
  end
data/spec/config_spec.rb CHANGED
@@ -8,7 +8,8 @@ describe AffairsOfState::Config do
8
8
  column: column,
9
9
  allow_blank: allow_blank,
10
10
  scopes: scopes,
11
- if: if_condition
11
+ if: if_condition,
12
+ prefix: prefix
12
13
  )
13
14
  end
14
15
  let(:column) { "state" }
@@ -16,6 +17,7 @@ describe AffairsOfState::Config do
16
17
  let(:allow_blank) { "sure" }
17
18
  let(:scopes) { nil }
18
19
  let(:if_condition) { "false" }
20
+ let(:prefix) { nil }
19
21
 
20
22
  subject { config }
21
23
 
@@ -39,6 +41,10 @@ describe AffairsOfState::Config do
39
41
  it "has :statuses and converts to strings and flattens" do
40
42
  expect(subject.statuses).to eq(["created", "destroyed"])
41
43
  end
44
+
45
+ it "has :methods_for_statuses which is the same key values" do
46
+ expect(subject.methods_for_statuses).to eq({ "created" => "created", "destroyed" => "destroyed" })
47
+ end
42
48
  end
43
49
 
44
50
  context "with invalid status" do
@@ -48,4 +54,16 @@ describe AffairsOfState::Config do
48
54
  expect { subject }.to raise_error(ArgumentError, "Affairs of State: 'new' is not a valid status")
49
55
  end
50
56
  end
57
+
58
+ context "with prefix" do
59
+ let(:prefix) { :admin }
60
+
61
+ it "has :statuses just the same" do
62
+ expect(subject.statuses).to eq(["created", "destroyed"])
63
+ end
64
+
65
+ it "has :methods_for_statuses" do
66
+ expect(subject.methods_for_statuses).to eq({ "created" => "admin_created", "destroyed" => "admin_destroyed" })
67
+ end
68
+ end
51
69
  end
data/spec/spec_helper.rb CHANGED
@@ -21,4 +21,5 @@ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'pies'")
21
21
  ActiveRecord::Base.connection.create_table(:pies) do |t|
22
22
  t.string :status
23
23
  t.string :super_status
24
+ t.string :sentiment
24
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: affairs_of_state
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin McPhillips
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-12 00:00:00.000000000 Z
11
+ date: 2021-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord