affairs_of_state 0.7.0 → 0.7.1

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
  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