stately_scopes 0.0.1

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
+ SHA1:
3
+ metadata.gz: 003e838787afee6e32b00bc0b1de8793f1e652b0
4
+ data.tar.gz: ec12b2749a9249961e1e7addf8fcfdf928f49ed3
5
+ SHA512:
6
+ metadata.gz: b644ea250dbb4a31678126f699ef27b9de1e23dfcb898ed7a8072586957af7389d9995d64a6d775ad5b958c27113d9521d91bcfcad20e86d14d94e6b0956220b
7
+ data.tar.gz: 245a8e943b2466e9783622bfbacf76135f6696a7193e3b38a3cce74c7161ee485b7d3b64f2e349256b1736a2495fb87bffa32c1278d3b91cac338bb8decc23b2
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.1
7
+
8
+ gemfile:
9
+ - Gemfile
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_record-scoping-with_state.gemspec
4
+ gemspec
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,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ t.libs.push 'spec'
8
+ end
9
+
10
+ task :default => [:test]
@@ -0,0 +1,3 @@
1
+ module StatelyScopes
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -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,4 @@
1
+ class Widget < ActiveRecord::Base
2
+ include StatelyScopes
3
+ scope :faked, -> { where(:fake => true) }
4
+ 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