affairs_of_state 0.4.1 → 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: e6950061957896a9e0bf23635b6b97d75c97fd09bf52eb51fa1fb30352842a00
4
- data.tar.gz: 8521df3d7183885b795982184e07adb4492a085f2fc46d0457af8f61f16d8f6b
3
+ metadata.gz: 393e826c50c889d987390c00c48332b5f25b36dacc8977a4b6ae872b031507c0
4
+ data.tar.gz: 268729f4f4e5d03616028ae9ad663e9333ec77be659c1eb17ff4ba78f9ea44f1
5
5
  SHA512:
6
- metadata.gz: 637f0bd6245bfc644145f0640fd690231a729b6a6557c034ccf0b8a07582e388335f6e49c9637428c739c4edbf15ccf19d867bb9a45ca87f0fbe5a5412e7f31f
7
- data.tar.gz: 9cfb5bff07dea9c39183c89f4469df774dc1470997707eff32b26d725bffa35a7e129dbf72369ef7557b44f0d55b805fce7fe9c8dcec44e5094fc2b88e6ed7e3
6
+ metadata.gz: b28c839c99db9cf1a7560766f46bda687825c23e6d17c2f20b1246d239990f26a450e5a9350c10f1ea191678b929ecf88c0a389be7620d13f37e26d3d02525eb
7
+ data.tar.gz: 88a2b5f1cefe5ac0017eeaa9b2c2d480895b51f31497adf049a8ce54dbd3966f3c9e8f472d1b300e9d650c644ca1cb3b67063ddcbf7067e914e21c42d96a05f6
@@ -0,0 +1,25 @@
1
+ name: CI
2
+
3
+ on: [ push, pull_request ]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ gemfile:
11
+ - "activerecord-6.0.gemfile"
12
+ - "activerecord-6.1.gemfile"
13
+ - "activerecord-latest.gemfile"
14
+ runs-on: ubuntu-latest
15
+ env:
16
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: 3.0.2
22
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
23
+ - name: Run tests
24
+ run: |
25
+ bundle exec rspec --format doc
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Affairs of State
2
2
 
3
- [![Build Status](https://travis-ci.org/kmcphillips/affairs_of_state.png?branch=master)](https://travis-ci.org/kmcphillips/affairs_of_state)
3
+ ![Build Status](https://github.com/kmcphillips/affairs_of_state/actions/workflows/ci.yml/badge.svg)
4
4
 
5
5
  You have an Active Record model. It nees to have multiple states, boolean convenience methods, simple validation, but not complex rules. This gem gives you this in a single line class method.
6
6
 
@@ -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
@@ -60,7 +66,7 @@ or
60
66
  affairs_of_state :active, :inactive, if: :only_validate_if_this_method_returns_true
61
67
  ```
62
68
 
63
- Currently it is limited only be called once per model.
69
+ It can be called multiple times per model, provided as each time is with a different column, and that none of the statuses overlap. If either of these are not true it will raise on load.
64
70
 
65
71
 
66
72
  ## Methods
@@ -72,23 +78,35 @@ widget = Widget.first
72
78
  widget.cancelled! if widget.active?
73
79
  ```
74
80
 
75
- You can also access all your statuses on the model like so:
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
+
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
78
- Widget::STATUSES # -> ["active", "cancelled"]
90
+ Widget.statuses # -> ["active", "cancelled"]
91
+ Widget.statuses(:status) # -> ["active", "cancelled"]
79
92
  ```
80
93
 
81
- It also provides scopes automagically:
94
+ It also provides scopes automagically, scoped by prefix if one is set:
82
95
 
83
96
  ```ruby
84
97
  Widget.active
85
98
  Widget.cancelled
86
99
  ```
100
+ ```ruby
101
+ Widget.admin_active
102
+ Widget.admin_cancelled
103
+ ```
87
104
 
88
- For select inputs in forms there is a convenience method that returns all states in the format expected by `options_for_select`
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:
89
106
 
90
107
  ```ruby
91
108
  <%= f.select :status, options_for_select(Widget.statuses_for_select) %>
109
+ <%= f.select :status, options_for_select(Widget.statuses_for_select(:status)) %>
92
110
  ```
93
111
 
94
112
 
@@ -16,12 +16,12 @@ Gem::Specification.new do |gem|
16
16
  gem.require_paths = ["lib"]
17
17
  gem.version = AffairsOfState::VERSION
18
18
 
19
- gem.add_dependency "activerecord", ">= 4.0"
20
- gem.add_dependency "activesupport", ">= 4.0"
19
+ gem.add_dependency "activerecord", "~> 6.0"
20
+ gem.add_dependency "activesupport", "~> 6.0"
21
21
 
22
- gem.add_development_dependency "rspec"
23
- gem.add_development_dependency "sqlite3"
24
- gem.add_development_dependency "pry"
25
- gem.add_development_dependency "rake"
22
+ gem.add_development_dependency "rspec", "~> 3.0"
23
+ gem.add_development_dependency "sqlite3", "~> 1.4.0"
24
+ gem.add_development_dependency "pry", "~> 0.12.0"
25
+ gem.add_development_dependency "rake", "~> 12"
26
26
 
27
27
  end
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec path: '..'
4
4
 
5
- gem 'activerecord', '~> 5.0'
5
+ gem 'activerecord', '~> 6.0'
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec path: '..'
4
4
 
5
- gem 'activerecord', '~> 4.0'
5
+ gem 'activerecord', '~> 6.1'
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec path: '..'
4
4
 
5
- gem 'activerecord', '~> 4.1'
5
+ gem 'activerecord'
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+ module AffairsOfState
3
+ module ActiveRecordExtension
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ def affairs_of_state(*statuses, column: :status, allow_blank: false, scopes: true, if: nil, prefix: nil)
8
+ # config object that defines behaviour
9
+ config = AffairsOfState::Config.new(
10
+ statuses: statuses,
11
+ prefix: prefix,
12
+ column: column,
13
+ allow_blank: !!allow_blank,
14
+ scopes: scopes,
15
+ if: binding.local_variable_get(:if)
16
+ )
17
+
18
+ # check for conflicts with existing calls
19
+ raise ArgumentError, "Affairs of State: #{ self } has already been called on `#{ config.column }`" if affairs_of_state_configs[config.column]
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
22
+ raise ArgumentError, "Affairs of State: #{ self } already has a status #{ overlapping_statuses }" if overlapping_statuses.any?
23
+
24
+ # status methods
25
+ config.methods_for_statuses.each do |status, method_name|
26
+ define_method("#{ method_name }?") do
27
+ self.send(config.column) == status
28
+ end
29
+
30
+ define_method("#{ method_name }!") do
31
+ self.send("#{ config.column }=", status)
32
+ self.save
33
+ end
34
+ end
35
+
36
+ # scopes
37
+ if config.scopes
38
+ config.methods_for_statuses.each do |status, method_name|
39
+ self.scope(method_name.to_sym, -> { where(config.column => status) })
40
+ end
41
+ end
42
+
43
+ # column validation
44
+ validates(config.column, inclusion: { in: config.statuses, allow_blank: config.allow_blank }, if: config.if)
45
+
46
+ # cache the config on the object
47
+ affairs_of_state_configs[config.column] = config
48
+
49
+ include InstanceMethods
50
+ extend SingletonMethods
51
+
52
+ true
53
+ end
54
+
55
+ def affairs_of_state_configs
56
+ @affairs_of_state_configs ||= {}
57
+ end
58
+ end
59
+
60
+ module InstanceMethods
61
+ end
62
+
63
+ module SingletonMethods
64
+ def statuses_for_select(column=nil)
65
+ statuses(column).map{ |s| [s.humanize, s] }
66
+ end
67
+
68
+ def statuses(column=nil)
69
+ if !column && affairs_of_state_configs.length == 1
70
+ affairs_of_state_configs.values.first.statuses
71
+ elsif !column && affairs_of_state_configs.length > 1
72
+ raise ArgumentError, "column is required"
73
+ elsif column
74
+ affairs_of_state_configs[column.to_sym]&.statuses
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,16 +1,27 @@
1
+ # frozen_string_literal: true
1
2
  module AffairsOfState
2
3
  class Config
3
- attr_accessor :column, :allow_blank, :scopes, :if
4
- attr_reader :statuses
4
+ attr_reader :statuses, :column, :allow_blank, :scopes, :if, :methods_for_statuses
5
5
 
6
- def statuses=(val)
7
- @statuses = val.flatten.map(&:to_s)
6
+ DISALLOWED_STATUSES = [ "new" ].freeze
8
7
 
8
+ def initialize(statuses:, column:, allow_blank:, scopes:, if:, prefix:)
9
+ @column = column
10
+ @allow_blank = !!allow_blank
11
+ @scopes = !!scopes
12
+ @if = binding.local_variable_get(:if)
13
+ @prefix = prefix.presence
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
9
22
  @statuses.each do |status|
10
- raise ArgumentError.new("Affairs of State: '#{ status }' is not a valid status") if ["new"].include?(status)
23
+ raise ArgumentError.new("Affairs of State: '#{ status }' is not a valid status") if DISALLOWED_STATUSES.include?(status)
11
24
  end
12
-
13
- @statuses
14
25
  end
15
26
  end
16
27
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module AffairsOfState
2
- VERSION = "0.4.1"
3
+ VERSION = "0.7.1"
3
4
  end
@@ -1,65 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  require "active_support"
2
3
  require "active_support/concern"
3
4
  require "active_record"
4
5
 
5
6
  require "affairs_of_state/version"
6
7
  require "affairs_of_state/config"
7
-
8
- module AffairsOfState
9
- extend ActiveSupport::Concern
10
-
11
- class_methods do
12
- def affairs_of_state(*statuses, column: :status, allow_blank: false, scopes: true, if: nil)
13
- raise ArgumentError.new("Affairs of State: cannot be invoked multiple times on the same model") if @affairs_of_state_config
14
-
15
- affairs_of_state_config.statuses = statuses
16
- affairs_of_state_config.column = column
17
- affairs_of_state_config.allow_blank = allow_blank
18
- affairs_of_state_config.scopes = scopes
19
- affairs_of_state_config.if = binding.local_variable_get(:if)
20
-
21
- const_set(:STATUSES, affairs_of_state_config.statuses)
22
-
23
- affairs_of_state_config.statuses.each do |status|
24
- define_method("#{ status }?") do
25
- self.send(self.class.affairs_of_state_config.column) == status
26
- end
27
-
28
- define_method("#{ status }!") do
29
- self.send("#{ self.class.affairs_of_state_config.column }=", status)
30
- self.save
31
- end
32
- end
33
-
34
- validates(affairs_of_state_config.column, inclusion: { in: affairs_of_state_config.statuses, allow_blank: affairs_of_state_config.allow_blank }, if: affairs_of_state_config.if)
35
-
36
- if affairs_of_state_config.scopes
37
- affairs_of_state_config.statuses.each do |status|
38
- self.scope(status.to_sym, -> { where(affairs_of_state_config.column => status) })
39
- end
40
- end
41
-
42
- include InstanceMethods
43
- extend SingletonMethods
44
-
45
- true
46
- end
47
-
48
- def affairs_of_state_config
49
- @affairs_of_state_config ||= AffairsOfState::Config.new
50
- end
51
- end
52
-
53
- module InstanceMethods
54
- end
55
-
56
- module SingletonMethods
57
- def statuses_for_select
58
- affairs_of_state_config.statuses.map{ |s| [s.humanize, s] }
59
- end
60
- end
61
- end
8
+ require "affairs_of_state/active_record_extension"
62
9
 
63
10
  ActiveSupport.on_load(:active_record) do
64
- ::ActiveRecord::Base.send :include, AffairsOfState
11
+ ::ActiveRecord::Base.send :include, AffairsOfState::ActiveRecordExtension
65
12
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe AffairsOfState do
@@ -6,57 +7,63 @@ describe AffairsOfState do
6
7
  affairs_of_state :active, :inactive, :cancelled
7
8
  end
8
9
 
9
- it "should set the constant" do
10
- expect(Pie::STATUSES).to eq(["active", "inactive", "cancelled"])
11
- end
10
+ subject { Pie }
12
11
 
13
12
  it "should validate the column is set" do
14
- expect(Pie.new(status: nil)).to_not be_valid
13
+ expect(subject.new(status: nil)).to_not be_valid
15
14
  end
16
15
 
17
16
  it "should validate that we're not setting it to something stupid" do
18
- expect(Pie.new(status: "delicious_pie")).to_not be_valid
17
+ expect(subject.new(status: "delicious_pie")).to_not be_valid
19
18
  end
20
19
 
21
20
  describe "boolean methods" do
22
21
  it "should find the set status" do
23
- p = Pie.new status: "active"
22
+ p = subject.new status: "active"
24
23
  expect(p.active?).to be_truthy
25
24
  end
26
25
 
27
26
  it "should not find if a different status is set" do
28
- p = Pie.new status: "inactive"
27
+ p = subject.new status: "inactive"
29
28
  expect(p.cancelled?).to be_falsy
30
29
  end
31
30
  end
32
31
 
33
32
  describe "update methods" do
34
33
  it "should set the value" do
35
- p = Pie.create! status: "active"
34
+ p = subject.create! status: "active"
36
35
  expect(p.inactive!).to be_truthy
37
36
  expect(p.status).to eq("inactive")
38
37
  end
39
38
  end
40
39
 
40
+ it "should have the statuses method with the nil default" do
41
+ expect(subject.statuses).to eq(["active", "inactive", "cancelled"])
42
+ end
43
+
44
+ it "should have the statuses method" do
45
+ expect(subject.statuses(:status)).to eq(["active", "inactive", "cancelled"])
46
+ end
47
+
41
48
  it "should provide a method to pass to dropdowns" do
42
- expect(Pie.statuses_for_select).to eq([["Active", "active"], ["Inactive", "inactive"], ["Cancelled", "cancelled"]])
49
+ expect(subject.statuses_for_select).to eq([["Active", "active"], ["Inactive", "inactive"], ["Cancelled", "cancelled"]])
43
50
  end
44
51
 
45
52
  describe "scopes" do
46
53
  it "should have a finder to match the status name" do
47
- Pie.create! status: "active"
48
- Pie.create! status: "inactive"
49
- Pie.create! status: "active"
50
- Pie.create! status: "cancelled"
51
-
52
- expect(Pie.active.size).to eq(2)
53
- expect(Pie.inactive.size).to eq(1)
54
- expect(Pie.cancelled.size).to eq(1)
54
+ subject.create! status: "active"
55
+ subject.create! status: "inactive"
56
+ subject.create! status: "active"
57
+ subject.create! status: "cancelled"
58
+
59
+ expect(subject.active.size).to eq(2)
60
+ expect(subject.inactive.size).to eq(1)
61
+ expect(subject.cancelled.size).to eq(1)
55
62
  end
56
63
  end
57
64
 
58
65
  after(:each) do
59
- Pie.destroy_all
66
+ subject.destroy_all
60
67
  end
61
68
  end
62
69
 
@@ -67,16 +74,18 @@ describe AffairsOfState do
67
74
  affairs_of_state :active, :inactive, column: :super_status
68
75
  end
69
76
 
77
+ subject { Pie2 }
78
+
70
79
  it "should validate the column is set" do
71
- expect(Pie2.new(status: nil, super_status: "active")).to be_valid
80
+ expect(subject.new(status: nil, super_status: "active")).to be_valid
72
81
  end
73
82
 
74
83
  it "should know the accessors" do
75
- expect(Pie2.new(status: nil, super_status: "inactive").inactive?).to be(true)
84
+ expect(subject.new(status: nil, super_status: "inactive").inactive?).to be(true)
76
85
  end
77
86
 
78
87
  it "should know the setters" do
79
- instance = Pie2.create!(status: nil, super_status: "inactive")
88
+ instance = subject.create!(status: nil, super_status: "inactive")
80
89
  expect(instance.active!).to be(true)
81
90
  expect(instance.super_status).to eq("active")
82
91
  end
@@ -89,8 +98,10 @@ describe AffairsOfState do
89
98
  affairs_of_state :active, :inactive, allow_blank: true
90
99
  end
91
100
 
101
+ subject { Pie3 }
102
+
92
103
  it "should validate the column is set" do
93
- expect(Pie3.new(status: nil)).to be_valid
104
+ expect(subject.new(status: nil)).to be_valid
94
105
  end
95
106
  end
96
107
 
@@ -101,8 +112,10 @@ describe AffairsOfState do
101
112
  affairs_of_state [:on, :off]
102
113
  end
103
114
 
115
+ subject { Pie4 }
116
+
104
117
  it "should work too if that's what floats your boat" do
105
- expect(Pie4::STATUSES).to eq(["on", "off"])
118
+ expect(subject.statuses).to eq(["on", "off"])
106
119
  end
107
120
  end
108
121
 
@@ -113,8 +126,10 @@ describe AffairsOfState do
113
126
  affairs_of_state :active, :inactive, scopes: false
114
127
  end
115
128
 
116
- it "should work too if that's what floats your boat" do
117
- expect(Pie5).to_not respond_to(:active)
129
+ subject { Pie5 }
130
+
131
+ it "should not respond if the scopes are not needed" do
132
+ expect(subject).to_not respond_to(:active)
118
133
  end
119
134
  end
120
135
 
@@ -127,15 +142,17 @@ describe AffairsOfState do
127
142
  attr_accessor :is_going_to_validate
128
143
  end
129
144
 
145
+ subject { Pie6 }
146
+
130
147
  it "should enforce the validation if the :if param is true" do
131
- p = Pie6.new
148
+ p = subject.new
132
149
  p.is_going_to_validate = true
133
150
  p.status = "pie"
134
151
  expect(p).to_not be_valid
135
152
  end
136
153
 
137
154
  it "should not enforce the validation if the :if param evaluates to false" do
138
- p = Pie6.new
155
+ p = subject.new
139
156
  p.is_going_to_validate = false
140
157
  p.status = "pie"
141
158
  expect(p).to be_valid
@@ -155,15 +172,17 @@ describe AffairsOfState do
155
172
  end
156
173
  end
157
174
 
175
+ subject { Pie7 }
176
+
158
177
  it "should enforce the validation if the :if param is true" do
159
- p = Pie7.new
178
+ p = subject.new
160
179
  p.is_going_to_validate = true
161
180
  p.status = "pie"
162
181
  expect(p).to_not be_valid
163
182
  end
164
183
 
165
184
  it "should not enforce the validation if the :if param evaluates to false" do
166
- p = Pie7.new
185
+ p = subject.new
167
186
  p.is_going_to_validate = false
168
187
  p.status = "pie"
169
188
  expect(p).to be_valid
@@ -177,13 +196,108 @@ describe AffairsOfState do
177
196
  end
178
197
 
179
198
  describe "multiple invocations" do
180
- it "raises an error" do
181
- expect(->{
182
- class Pie9 < ActiveRecord::Base
183
- affairs_of_state :not_important
184
- affairs_of_state :something
199
+ class Pie9 < ActiveRecord::Base
200
+ self.table_name = "pies"
201
+
202
+ affairs_of_state :active, :inactive
203
+ affairs_of_state :moderated, :unmoderated, column: :super_status
204
+ end
205
+
206
+ subject { Pie9 }
207
+
208
+ it "declares two status columns" do
209
+ p = subject.new
210
+ p.inactive!
211
+ p.unmoderated!
212
+ expect(p).to be_inactive
213
+ expect(p).to be_unmoderated
214
+ end
215
+
216
+ it "raises if called twice on the same column" do
217
+ expect {
218
+ class Pie10 < ActiveRecord::Base
219
+ self.table_name = "pies"
220
+
221
+ affairs_of_state :active, :inactive
222
+ affairs_of_state :moderated, :unmoderated
223
+ end
224
+ }.to raise_error(ArgumentError)
225
+ end
226
+
227
+ it "raises if called twice with the same status in both" do
228
+ expect {
229
+ class Pie11 < ActiveRecord::Base
230
+ self.table_name = "pies"
231
+
232
+ affairs_of_state :active, :inactive
233
+ affairs_of_state :dormant, :active, column: :super_status
185
234
  end
186
- }).to raise_error(ArgumentError, "Affairs of State: cannot be invoked multiple times on the same model")
235
+ }.to raise_error(ArgumentError)
236
+ end
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
+
249
+ it "raises if statuses is called with no argument" do
250
+ expect {
251
+ subject.statuses
252
+ }.to raise_error(ArgumentError)
253
+ end
254
+
255
+ it "returns the statuses for the column" do
256
+ expect(subject.statuses(:status)).to eq(["active", "inactive"])
257
+ expect(subject.statuses("super_status")).to eq(["moderated", "unmoderated"])
258
+ end
259
+
260
+ it "raises if statuses_for_select is called with no argument" do
261
+ expect {
262
+ subject.statuses_for_select
263
+ }.to raise_error(ArgumentError)
264
+ end
265
+
266
+ it "returns the statuses_for_select for the column" do
267
+ expect(subject.statuses_for_select(:status)).to eq([["Active", "active"], ["Inactive", "inactive"]])
268
+ expect(subject.statuses_for_select("super_status")).to eq([["Moderated", "moderated"], ["Unmoderated", "unmoderated"]])
269
+ end
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])
187
301
  end
188
302
  end
189
303
  end
data/spec/config_spec.rb CHANGED
@@ -1,47 +1,69 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe AffairsOfState::Config do
4
- subject{ AffairsOfState::Config.new }
5
+ let(:config) do
6
+ AffairsOfState::Config.new(
7
+ statuses: statuses,
8
+ column: column,
9
+ allow_blank: allow_blank,
10
+ scopes: scopes,
11
+ if: if_condition,
12
+ prefix: prefix
13
+ )
14
+ end
15
+ let(:column) { "state" }
16
+ let(:statuses) { [ :created, [ :destroyed ] ] }
17
+ let(:allow_blank) { "sure" }
18
+ let(:scopes) { nil }
19
+ let(:if_condition) { "false" }
20
+ let(:prefix) { nil }
5
21
 
6
- describe "accessors" do
7
- let(:expected){ double }
22
+ subject { config }
8
23
 
24
+ describe "accessors" do
9
25
  it "has :column" do
10
- subject.column = expected
11
- expect(subject.column).to eq(expected)
26
+ expect(subject.column).to eq(column)
12
27
  end
13
28
 
14
29
  it "has :allow_blank" do
15
- subject.allow_blank = expected
16
- expect(subject.allow_blank).to eq(expected)
30
+ expect(subject.allow_blank).to be(true)
17
31
  end
18
32
 
19
33
  it "has :scopes" do
20
- subject.scopes = expected
21
- expect(subject.scopes).to eq(expected)
34
+ expect(subject.scopes).to be(false)
22
35
  end
23
36
 
24
37
  it "has :if" do
25
- subject.if = expected
26
- expect(subject.if).to eq(expected)
38
+ expect(subject.if).to eq(if_condition)
27
39
  end
28
- end
29
40
 
30
- describe "#statuses=" do
31
- it "converts to string" do
32
- subject.statuses = [:a, :b]
33
- expect(subject.statuses).to eq(["a", "b"])
41
+ it "has :statuses and converts to strings and flattens" do
42
+ expect(subject.statuses).to eq(["created", "destroyed"])
34
43
  end
35
44
 
36
- it "flattens" do
37
- subject.statuses = ["a", [:b]]
38
- expect(subject.statuses).to eq(["a", "b"])
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" })
39
47
  end
48
+ end
49
+
50
+ context "with invalid status" do
51
+ let(:statuses) { [ "new" ] }
40
52
 
41
53
  it "makes sure no invalid statuses are allowed" do
42
- expect(->{
43
- subject.statuses = [:new]
44
- }).to raise_error(ArgumentError, "Affairs of State: 'new' is not a valid status")
54
+ expect { subject }.to raise_error(ArgumentError, "Affairs of State: 'new' is not a valid status")
55
+ end
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" })
45
67
  end
46
68
  end
47
69
  end
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  require "affairs_of_state"
2
3
 
3
4
  require "pry"
5
+ require "sqlite3"
4
6
 
5
7
  RSpec.configure do |config|
6
8
  config.run_all_when_everything_filtered = true
9
+ config.filter_run_when_matching :focus
7
10
  end
8
11
 
9
- ## Create an AR model to test with
12
+ # Create an AR model to test with
10
13
  I18n.enforce_available_locales = false
11
14
 
12
15
  ActiveRecord::Base.establish_connection(
@@ -18,4 +21,5 @@ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'pies'")
18
21
  ActiveRecord::Base.connection.create_table(:pies) do |t|
19
22
  t.string :status
20
23
  t.string :super_status
24
+ t.string :sentiment
21
25
  end
metadata CHANGED
@@ -1,99 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: affairs_of_state
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin McPhillips
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-10 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
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '6.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.0'
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '4.0'
33
+ version: '6.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '4.0'
40
+ version: '6.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '3.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sqlite3
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 1.4.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.4.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: pry
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 0.12.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 0.12.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '12'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '12'
97
97
  description: Add a simple state to a gem, without all the hassle of a complex state
98
98
  machine.
99
99
  email:
@@ -102,19 +102,19 @@ executables: []
102
102
  extensions: []
103
103
  extra_rdoc_files: []
104
104
  files:
105
+ - ".github/workflows/ci.yml"
105
106
  - ".gitignore"
106
107
  - ".rspec"
107
- - ".travis.yml"
108
108
  - Gemfile
109
109
  - LICENSE
110
110
  - README.md
111
111
  - Rakefile
112
112
  - affairs_of_state.gemspec
113
- - gemfiles/activerecord40.gemfile
114
- - gemfiles/activerecord41.gemfile
115
- - gemfiles/activerecord42.gemfile
116
- - gemfiles/activerecord50.gemfile
113
+ - gemfiles/activerecord-6.0.gemfile
114
+ - gemfiles/activerecord-6.1.gemfile
115
+ - gemfiles/activerecord-latest.gemfile
117
116
  - lib/affairs_of_state.rb
117
+ - lib/affairs_of_state/active_record_extension.rb
118
118
  - lib/affairs_of_state/config.rb
119
119
  - lib/affairs_of_state/version.rb
120
120
  - spec/affairs_of_state_spec.rb
@@ -125,7 +125,7 @@ homepage: http://github.com/kmcphillips/affairs_of_state
125
125
  licenses:
126
126
  - MIT
127
127
  metadata: {}
128
- post_install_message:
128
+ post_install_message:
129
129
  rdoc_options: []
130
130
  require_paths:
131
131
  - lib
@@ -140,8 +140,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
142
  requirements: []
143
- rubygems_version: 3.0.4
144
- signing_key:
143
+ rubygems_version: 3.2.22
144
+ signing_key:
145
145
  specification_version: 4
146
146
  summary: You have an Active Record model. It nees to have multiple states, but not
147
147
  complex rules. This gem gives you validation, easy check and change methods, and
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- language: ruby
2
- script: bundle exec rspec
3
- sudo: false
4
- rvm:
5
- - "2.1.0"
6
- - "2.2.2"
7
- - "2.3.1"
8
-
9
- gemfile:
10
- - Gemfile
11
- - gemfiles/activerecord40.gemfile
12
- - gemfiles/activerecord41.gemfile
13
- - gemfiles/activerecord42.gemfile
14
- - gemfiles/activerecord50.gemfile
15
-
16
- matrix:
17
- exclude:
18
- - rvm: "2.1.0"
19
- gemfile: Gemfile
20
- - rvm: "2.1.0"
21
- gemfile: gemfiles/activerecord50.gemfile
@@ -1,5 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec path: '..'
4
-
5
- gem 'activerecord', '~> 4.2'