action_state 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 66bc5c3dbb72d3061e32ebd722563bf5f1ea6d00714604c27c6720b7e49d8d72
4
+ data.tar.gz: bd61f346df26a1ca17c8c29b39ae9e57544a0082026a948788819fbff74499e6
5
+ SHA512:
6
+ metadata.gz: 45d45ce7c60a9353c05f7b0a727aadc817d60513511ba7018b7e76383737bc294ceda47c9b4dcbce8213fdc1a3d386320f93031103f42290ea0885368206ac6d
7
+ data.tar.gz: 7d1149caa26980a04fd2c7059f54675ab0afcc806aaed3aeb8273a11b9c8a81b8eb8104f4e8e30db8dda4a291f7699282b6e56b7e16ac42a39a7e939eb42af07
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Joel Drapper
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # action_state
2
+
3
+ ActionState provides a simple DSL for defining model states and allows you to query the state as an ActiveRecord scope on the class and a predicate on the instance.
4
+
5
+ For example, the following state definition defines a class scope `Article.published` and an instance predicate `article.published?`.
6
+
7
+ ```ruby
8
+ class Article < ApplicationRecord
9
+ state(:published) { where(published_at: ..Time.current) }
10
+ ...
11
+ end
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ActionState supports a small subset of ActiveRecord queries for the predicate definition, and delegates the scope definition to ActiveRecord.
17
+
18
+ It's not meant to comprehensively support every possible ActiveRecord query; rather it supports a few features that tend to lend themselves well to predicate definitions.
19
+
20
+ ### `where`
21
+
22
+ The `where` method checks for inclusion in an Enumerable, coverage by a Range, and equality with other types of value.
23
+
24
+ #### Inclusion in an Enumerable
25
+
26
+ ```ruby
27
+ state(:crafter) { where(role: ["designer", "developer"]) }
28
+ ```
29
+
30
+ #### Covered by a Range
31
+
32
+ ```ruby
33
+ state(:negative) { where(stars: 1..4 }
34
+ state(:indifferent) { where(stars: 5..6) }
35
+ state(:positive) { where(stars: 7..9) }
36
+
37
+ state(:recently_published) { where(published_at: 1.week.ago..) }
38
+ ```
39
+
40
+ #### Equality
41
+
42
+ ```ruby
43
+ state(:featured) { where(featured: true) }
44
+ ```
45
+
46
+ ### `where.not`
47
+
48
+ The counterpart to `where` is `where.not` which checks for exclusion from an Enumerable or Range, and inequality with other types of value.
49
+
50
+ ```ruby
51
+ state(:deleted) { where.not(deleted_at: nil) }
52
+ ```
53
+
54
+ ### `excluding`
55
+
56
+ The `excluding` method excludes specific instances of a model.
57
+
58
+ ```ruby
59
+ state(:normal) { excluding(special_post) }
60
+ ```
61
+
62
+ ### Passing arguments
63
+
64
+ States can also be defined to accept arguments.
65
+
66
+ ```ruby
67
+ state(:before) { |whenever| where(created_at: ..whenever) }
68
+ state(:after) { |whenever| where(created_at: whenever..) }
69
+ ```
70
+
71
+ ### Composing states
72
+
73
+ You can chain query methods together to form more complex queries.
74
+
75
+ ```ruby
76
+ state(:can_edit) { where(role: "admin").where.not(disabled: true) }
77
+ ```
78
+
79
+ You can also compose multiple states together.
80
+
81
+ ```ruby
82
+ state(:published) { where(published: true) }
83
+ state(:featured) { published.where(featured: true) }
84
+ ```
85
+
86
+ ## Installation
87
+
88
+ Add this line to your application's Gemfile:
89
+
90
+ ```ruby
91
+ gem "action_state"
92
+ ```
93
+
94
+ And then execute:
95
+
96
+ ```other
97
+ $ bundle
98
+ ```
99
+
100
+ Or install it yourself as:
101
+
102
+ ```other
103
+ $ gem install action_state
104
+ ```
105
+
106
+ Finally, include `ActionState` in your model class or `ApplicationRecord`:
107
+
108
+ ```ruby
109
+ class ApplicationRecord < ActiveRecord::Base
110
+ include ActionState
111
+ ...
112
+ end
113
+ ```
114
+
115
+ ## Contributing
116
+
117
+ Contributions are welcome. Please feel free top open a PR / issue / discussion.
118
+
119
+ ## License
120
+
121
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
122
+
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,63 @@
1
+ module ActionState
2
+ class Predicate
3
+ attr_reader :result
4
+
5
+ def initialize(record)
6
+ @record = record
7
+ @result = true
8
+ end
9
+
10
+ def excluding(*records)
11
+ return self unless result
12
+
13
+ @result = false if records.include?(@record)
14
+
15
+ self
16
+ end
17
+
18
+ def where(**kwargs)
19
+ return self unless @result
20
+
21
+ @result = false if kwargs.any? do |k, v|
22
+ case v
23
+ when ::Range
24
+ !v.cover? @record.send(k)
25
+ when ::Enumerable
26
+ !v.include? @record.send(k)
27
+ else
28
+ v != @record.send(k)
29
+ end
30
+ end
31
+
32
+ self
33
+ end
34
+
35
+ def not(**kwargs)
36
+ return self unless @result
37
+
38
+ @result = false if kwargs.any? do |k, v|
39
+ attribute = @record.send(k)
40
+ next true if attribute.nil? && !v.nil?
41
+
42
+ case v
43
+ when ::Range
44
+ v.cover? attribute
45
+ when ::Enumerable
46
+ v.include? attribute
47
+ else
48
+ v == attribute
49
+ end
50
+ end
51
+
52
+ self
53
+ end
54
+
55
+ def method_missing(method_name, *args, **kwargs, &block)
56
+ return self unless @result
57
+
58
+ @result = false unless @record.send("#{method_name}?", *args, **kwargs, &block)
59
+
60
+ self
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,4 @@
1
+ module ActionState
2
+ class Railtie < ::Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module ActionState
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,17 @@
1
+ require "action_state/version"
2
+ require "action_state/railtie"
3
+ require "action_state/predicate"
4
+
5
+ module ActionState
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def state(name, &block)
10
+ scope(name, Proc.new(&block))
11
+
12
+ define_method("#{name}?") do |*args, **kwargs|
13
+ Predicate.new(self).instance_exec(*args, **kwargs, &block).result
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :action_state do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_state
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Joel Drapper
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ description: Quickly define model state predicates and scopes at the same time.
28
+ email:
29
+ - joel@drapper.me
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - lib/action_state.rb
38
+ - lib/action_state/predicate.rb
39
+ - lib/action_state/railtie.rb
40
+ - lib/action_state/version.rb
41
+ - lib/tasks/action_state_tasks.rake
42
+ homepage: https://github.com/joeldrapper/action_state
43
+ licenses:
44
+ - MIT
45
+ metadata:
46
+ homepage_uri: https://github.com/joeldrapper/action_state
47
+ source_code_uri: https://github.com/joeldrapper/action_state
48
+ changelog_uri: https://github.com/joeldrapper/action_state
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 3.3.7
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Small DSL for defining model states.
68
+ test_files: []