stately_scopes 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +124 -0
- data/Rakefile +10 -0
- data/lib/stately_scopes/version.rb +3 -0
- data/lib/stately_scopes.rb +45 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/stately_scopes_spec.rb +57 -0
- data/spec/support/widget.rb +4 -0
- data/stately_scopes.gemspec +27 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 003e838787afee6e32b00bc0b1de8793f1e652b0
|
4
|
+
data.tar.gz: ec12b2749a9249961e1e7addf8fcfdf928f49ed3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b644ea250dbb4a31678126f699ef27b9de1e23dfcb898ed7a8072586957af7389d9995d64a6d775ad5b958c27113d9521d91bcfcad20e86d14d94e6b0956220b
|
7
|
+
data.tar.gz: 245a8e943b2466e9783622bfbacf76135f6696a7193e3b38a3cce74c7161ee485b7d3b64f2e349256b1736a2495fb87bffa32c1278d3b91cac338bb8decc23b2
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nicholas Bruning
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# StatelyScopes
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/thetron/stately_scopes.svg?branch=master)](https://travis-ci.org/thetron/stately_scopes)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/thetron/stately_scopes.png)](https://codeclimate.com/github/thetron/stately_scopes)
|
5
|
+
|
6
|
+
An ActiveRecord extension so small, it's almost silly - but it is kinda helpful.
|
7
|
+
|
8
|
+
I've found that when developing Rails apps, I tend to almost always pair each
|
9
|
+
scope with an instance method which returns a boolean indicating whether the
|
10
|
+
object is included inside a given scope.
|
11
|
+
|
12
|
+
This gem simply automates that method creation for you. Nothing super fancy,
|
13
|
+
and you might consider replacing the state methods with your own, more
|
14
|
+
efficient, implementations - but it's great for early stages of development, or
|
15
|
+
providing a comparative case for unit tests.
|
16
|
+
|
17
|
+
|
18
|
+
## Example
|
19
|
+
|
20
|
+
Using a small `Event` model:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class Event < ActiveRecord::Base
|
24
|
+
include StatelyScopes
|
25
|
+
scope :upcoming, -> { where ("starts_at > ?", Time.now) }
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
old_event = Event.create(:starts_at => 1.day.ago)
|
31
|
+
upcoming_event = Event.create(:starts_at => 1.day.from_now)
|
32
|
+
|
33
|
+
old_event.upcoming? # => false
|
34
|
+
upcoming_event.upcoming? # => true
|
35
|
+
```
|
36
|
+
|
37
|
+
|
38
|
+
## Installation
|
39
|
+
|
40
|
+
Add this line to your application's Gemfile:
|
41
|
+
|
42
|
+
gem 'stately_scopes'
|
43
|
+
|
44
|
+
And then execute:
|
45
|
+
|
46
|
+
$ bundle
|
47
|
+
|
48
|
+
Or install it yourself as:
|
49
|
+
|
50
|
+
$ gem 'stately_scopes'
|
51
|
+
|
52
|
+
|
53
|
+
## Usage
|
54
|
+
|
55
|
+
The gem automatically aliases the existing `scope` method provided by
|
56
|
+
ActiveRecord, so all of your models will have the new state methods by default.
|
57
|
+
|
58
|
+
The helper methods will have the same name as your scopes, with a `?` appended.
|
59
|
+
|
60
|
+
Eg:
|
61
|
+
|
62
|
+
`scope :upcoming, -> { ... }` will generate `.upcoming?`
|
63
|
+
and
|
64
|
+
`scope :spam -> { ... }` will generate `.spam?`
|
65
|
+
|
66
|
+
You get the picture.
|
67
|
+
|
68
|
+
If you're wanting to avoid the automatically generated state methods on a given
|
69
|
+
scope, you can simply use `scope_without_state` instead of `scope`.
|
70
|
+
|
71
|
+
|
72
|
+
## Configuration
|
73
|
+
|
74
|
+
You can turn off the automatic aliasing of `scope`, and explicitly call
|
75
|
+
`scope_with_state` instead, for each scope that you'd like to have generated
|
76
|
+
state method for. To do that, add the following initializer:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
# config/initializers/active_record-scoping-with_state.rb
|
80
|
+
StatelyScopes.configure do |config|
|
81
|
+
config.alias_scope_method = false
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
|
86
|
+
## Caveats
|
87
|
+
|
88
|
+
It should be noted that the instance methods do use a database query in order
|
89
|
+
to establish a model instance's state. Arguably not ideal, however the query is
|
90
|
+
as efficient as possible (I think?).
|
91
|
+
|
92
|
+
If you have performance concerns, I would recommend overriding the generated
|
93
|
+
state methods for production use. In this case, this gem can still be used
|
94
|
+
in test cases by calling `.has_scoped_state(scope_name)` on your model instances.
|
95
|
+
In this way, you can help validate that your overridden state methods are
|
96
|
+
congruent to the conditions in your scope.
|
97
|
+
|
98
|
+
Using the above `Event` model again, however the `upcoming?` method has been
|
99
|
+
overridden with:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
# app/models/event.rb
|
103
|
+
|
104
|
+
def upcoming?
|
105
|
+
self.starts_at > Time.now
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
Obviously this is better than hitting the database, however we'd like to write
|
110
|
+
a test case that ensures that the new method is the equivalent of the generated
|
111
|
+
one - so we can do something like this:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
future_event = Event.create(:starts_at => 5.days.from_now)
|
115
|
+
assert_equal future_event.upcoming?, future_event.has_scoped_state?(:upcoming)
|
116
|
+
```
|
117
|
+
|
118
|
+
## Contributing
|
119
|
+
|
120
|
+
1. Fork it ( http://github.com/thetron/active_record-scoping-with_state/fork )
|
121
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
122
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
123
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
124
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/module/aliasing'
|
3
|
+
|
4
|
+
module StatelyScopes
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_eval do
|
9
|
+
class << self
|
10
|
+
alias_method_chain :scope, :state if StatelyScopes.configuration.alias_scope_method
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_scoped_state?(name)
|
16
|
+
self.class.send(name.to_sym).exists?(self.id)
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def scope_with_state(name, body, &block)
|
21
|
+
if StatelyScopes.configuration.alias_scope_method
|
22
|
+
scope_without_state name, body, &block
|
23
|
+
else
|
24
|
+
scope name, body, &block
|
25
|
+
end
|
26
|
+
class_eval "def #{name}?() self.has_scoped_state?(#{name}) end"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
def configure(&block)
|
32
|
+
yield(StatelyScopes::Configuration.configuration)
|
33
|
+
end
|
34
|
+
|
35
|
+
def configuration
|
36
|
+
StatelyScopes::Configuration.configuration
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Configuration
|
41
|
+
def self.configuration
|
42
|
+
@@configuration ||= OpenStruct.new(:alias_scope_method => true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require(:default)
|
3
|
+
|
4
|
+
require 'active_record'
|
5
|
+
require 'stately_scopes'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
require 'minitest/autorun'
|
9
|
+
require 'minitest/spec'
|
10
|
+
require 'minitest/mock'
|
11
|
+
require 'minitest/pride'
|
12
|
+
|
13
|
+
module MiniTest
|
14
|
+
class Spec
|
15
|
+
class << self
|
16
|
+
alias_method :context, :describe
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
#ActiveRecord::Base.logger = Logger.new(STDERR)
|
23
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
24
|
+
|
25
|
+
ActiveRecord::Schema.define do
|
26
|
+
create_table :widgets do |table|
|
27
|
+
table.column :fake, :boolean
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def reload_widget
|
32
|
+
Object.send(:remove_const, :Widget)
|
33
|
+
load 'support/widget.rb'
|
34
|
+
end
|
35
|
+
|
36
|
+
load 'support/widget.rb'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe StatelyScopes do
|
4
|
+
it "aliases the scope method" do
|
5
|
+
Widget.public_methods.must_include :scope_without_state, "Expected widget to alias `scope'"
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ".has_scoped_state?" do
|
9
|
+
context "when object is in the scope" do
|
10
|
+
it "returns true" do
|
11
|
+
widget = Widget.create(:fake => true)
|
12
|
+
widget.has_scoped_state?(:faked).must_equal true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when object is outside the scope" do
|
17
|
+
it "returns false" do
|
18
|
+
widget = Widget.create(:fake => false)
|
19
|
+
widget.has_scoped_state?(:faked).must_equal false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#scope_with_state" do
|
25
|
+
it "defines a scope" do
|
26
|
+
Widget.public_methods.must_include :faked
|
27
|
+
end
|
28
|
+
|
29
|
+
it "defines a state instance method" do
|
30
|
+
Widget.new.public_methods.must_include :faked?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "configuration" do
|
35
|
+
context "when alias_scope_method = false" do
|
36
|
+
it "does not alias the scope method" do
|
37
|
+
StatelyScopes.configure { |c| c.alias_scope_method = false }
|
38
|
+
reload_widget
|
39
|
+
Widget.public_methods.wont_include :scope_without_state, "Expected widget to not alias `scope'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#configure" do
|
44
|
+
it "yields the configuration" do
|
45
|
+
StatelyScopes.configure do |config|
|
46
|
+
config.must_equal StatelyScopes::Configuration.configuration
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#configuration" do
|
52
|
+
it "sets alias_scope_method to true by default" do
|
53
|
+
StatelyScopes.configuration.alias_scope_method.must_equal true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'stately_scopes/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "stately_scopes"
|
8
|
+
spec.version = StatelyScopes::VERSION
|
9
|
+
spec.authors = ["Nicholas Bruning"]
|
10
|
+
spec.email = ["nicholas@bruning.com.au"]
|
11
|
+
spec.summary = %q{Automatically creates state query methods for each of your model's scopes.}
|
12
|
+
spec.description = %q{I've found that when developing Rails apps, I tend to almost always pair each scope with an instance method which returns a boolean indicating whether the object is included inside that scope.\n\nThis gem simply automatically creates that method for you. Nothing super fancy, and you might consider replacing the state methods with your own, more efficient, implementations - but it's great for early stages of development, or providing a comparative case for unit tests.}
|
13
|
+
spec.homepage = "http://github.com/thetron/stately_scopes"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "activerecord", "~> 4.0.4"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "minitest"
|
26
|
+
spec.add_development_dependency "sqlite3"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stately_scopes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Bruning
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.0.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.0.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: I've found that when developing Rails apps, I tend to almost always pair
|
84
|
+
each scope with an instance method which returns a boolean indicating whether the
|
85
|
+
object is included inside that scope.\n\nThis gem simply automatically creates that
|
86
|
+
method for you. Nothing super fancy, and you might consider replacing the state
|
87
|
+
methods with your own, more efficient, implementations - but it's great for early
|
88
|
+
stages of development, or providing a comparative case for unit tests.
|
89
|
+
email:
|
90
|
+
- nicholas@bruning.com.au
|
91
|
+
executables: []
|
92
|
+
extensions: []
|
93
|
+
extra_rdoc_files: []
|
94
|
+
files:
|
95
|
+
- ".gitignore"
|
96
|
+
- ".travis.yml"
|
97
|
+
- Gemfile
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
100
|
+
- Rakefile
|
101
|
+
- lib/stately_scopes.rb
|
102
|
+
- lib/stately_scopes/version.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
- spec/stately_scopes_spec.rb
|
105
|
+
- spec/support/widget.rb
|
106
|
+
- stately_scopes.gemspec
|
107
|
+
homepage: http://github.com/thetron/stately_scopes
|
108
|
+
licenses:
|
109
|
+
- MIT
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.2.2
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Automatically creates state query methods for each of your model's scopes.
|
131
|
+
test_files:
|
132
|
+
- spec/spec_helper.rb
|
133
|
+
- spec/stately_scopes_spec.rb
|
134
|
+
- spec/support/widget.rb
|