sexy_scopes 0.5.0 → 0.5.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.
- data/lib/sexy_scopes.rb +8 -0
- data/lib/sexy_scopes/active_record.rb +4 -90
- data/lib/sexy_scopes/active_record/class_methods.rb +47 -0
- data/lib/sexy_scopes/active_record/dynamic_methods.rb +69 -0
- data/lib/sexy_scopes/arel.rb +2 -3
- data/lib/sexy_scopes/arel/{predicate_wrappers.rb → boolean_methods.rb} +1 -3
- data/lib/sexy_scopes/arel/{expression_methods.rb → math_methods.rb} +5 -1
- data/lib/sexy_scopes/expression_wrappers.rb +7 -0
- data/lib/sexy_scopes/predicate_wrappers.rb +6 -0
- data/lib/sexy_scopes/version.rb +9 -1
- data/lib/sexy_scopes/wrappers.rb +2 -2
- data/sexy_scopes.gemspec +4 -2
- data/spec/active_record_spec.rb +75 -0
- data/spec/boolean_methods_spec.rb +45 -0
- data/spec/fixtures/models.rb +2 -0
- data/spec/fixtures/schema.rb +9 -0
- data/spec/matchers/be_extended_by.rb +6 -0
- data/spec/matchers/convert_to_sql.rb +13 -0
- data/spec/{expression_methods_spec.rb → math_methods_spec.rb} +11 -3
- data/spec/predicate_methods_spec.rb +1 -9
- data/spec/spec_helper.rb +13 -27
- metadata +63 -23
- data/lib/sexy_scopes/arel/expression_wrappers.rb +0 -9
- data/spec/sexy_scopes_spec.rb +0 -47
data/lib/sexy_scopes.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
require 'active_support/dependencies/autoload'
|
2
|
+
|
1
3
|
module SexyScopes
|
2
4
|
%w( Version VERSION ).each do |constant|
|
3
5
|
autoload constant, 'sexy_scopes/version'
|
4
6
|
end
|
7
|
+
|
8
|
+
extend ActiveSupport::Autoload
|
9
|
+
|
10
|
+
autoload :Wrappers
|
11
|
+
autoload :ExpressionWrappers
|
12
|
+
autoload :PredicateWrappers
|
5
13
|
end
|
6
14
|
|
7
15
|
if defined? Rails::Railtie
|
@@ -1,92 +1,6 @@
|
|
1
|
-
require 'delegate'
|
2
1
|
require 'active_record'
|
3
|
-
require 'sexy_scopes/
|
4
|
-
require 'sexy_scopes/
|
2
|
+
require 'sexy_scopes/active_record/class_methods'
|
3
|
+
require 'sexy_scopes/active_record/dynamic_methods'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
include Wrappers
|
9
|
-
|
10
|
-
# Creates and extends an Arel <tt>Attribute</tt> representing the table's column with
|
11
|
-
# the given <tt>name</tt>.
|
12
|
-
#
|
13
|
-
# @param [String, Symbol] name The attribute name
|
14
|
-
#
|
15
|
-
# @note Please note that no exception is raised if no such column actually exists.
|
16
|
-
#
|
17
|
-
# @example
|
18
|
-
# User.where(User.attribute(:score) > 1000)
|
19
|
-
# # => SELECT "users".* FROM "users" WHERE ("users"."score" > 1000)
|
20
|
-
#
|
21
|
-
def attribute(name)
|
22
|
-
attribute = arel_table[name]
|
23
|
-
extend_expression(attribute)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Creates and extends an Arel <tt>SqlLiteral</tt> instance for the given <tt>expression</tt>,
|
27
|
-
# first converted to a string using <tt>to_s</tt>.
|
28
|
-
#
|
29
|
-
# @param [String, #to_s] expression Any SQL expression.
|
30
|
-
#
|
31
|
-
# @example
|
32
|
-
# def Circle.with_perimeter_smaller_than(perimeter)
|
33
|
-
# where sql(2 * Math::PI) * radius < perimeter
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# Circle.with_perimeter_smaller_than(20)
|
37
|
-
# # => SELECT "circles".* FROM "circles" WHERE (6.283185307179586 * "circles"."radius" < 20)
|
38
|
-
#
|
39
|
-
def sql_literal(expression)
|
40
|
-
::Arel.sql(expression.to_s).tap do |literal|
|
41
|
-
extend_expression(literal)
|
42
|
-
extend_predicate(literal)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
alias_method :sql, :sql_literal
|
46
|
-
|
47
|
-
# @!visibility private
|
48
|
-
def respond_to?(method_name, include_private = false) # :nodoc:
|
49
|
-
super || column_names.include?(method_name.to_s)
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
# Equivalent to calling {#attribute} with the missing method's <tt>name</tt> if the table
|
54
|
-
# has a column with that name.
|
55
|
-
#
|
56
|
-
# Delegates to superclass implementation otherwise, eventually raising <tt>NoMethodError</tt>.
|
57
|
-
#
|
58
|
-
# @see #attribute
|
59
|
-
#
|
60
|
-
# @note Due to the way this works, be careful not to use this syntactic sugar with existing
|
61
|
-
# <tt>ActiveRecord::Base</tt> methods (see last example).
|
62
|
-
#
|
63
|
-
# @raise [NoMethodError] if the table has no corresponding column
|
64
|
-
#
|
65
|
-
# @example
|
66
|
-
# # Suppose the "users" table has an "email" column, then these are equivalent:
|
67
|
-
# User.email
|
68
|
-
# User.attribute(:email)
|
69
|
-
#
|
70
|
-
# @example
|
71
|
-
# # Here is the previous example (from `attribute`) rewritten:
|
72
|
-
# User.where(User.score > 1000)
|
73
|
-
# # => SELECT "users".* FROM "users" WHERE ("users"."score" > 1000)
|
74
|
-
#
|
75
|
-
# @example
|
76
|
-
# # Don't use it with existing `ActiveRecord::Base` methods, i.e. `name`:
|
77
|
-
# User.name # => "User"
|
78
|
-
# # In these cases you'll have to use `attribute` explicitely
|
79
|
-
# User.attribute(:name)
|
80
|
-
#
|
81
|
-
def method_missing(name, *args)
|
82
|
-
if column_names.include?(name.to_s)
|
83
|
-
attribute(name)
|
84
|
-
else
|
85
|
-
super
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Add these methods to Active Record
|
91
|
-
::ActiveRecord::Base.extend SexyScopes::ActiveRecord
|
92
|
-
end
|
5
|
+
ActiveRecord::Base.extend SexyScopes::ActiveRecord::ClassMethods
|
6
|
+
ActiveRecord::Base.extend SexyScopes::ActiveRecord::DynamicMethods
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'sexy_scopes/arel'
|
2
|
+
require 'sexy_scopes/wrappers'
|
3
|
+
|
4
|
+
module SexyScopes
|
5
|
+
module ActiveRecord
|
6
|
+
module ClassMethods
|
7
|
+
include Wrappers
|
8
|
+
|
9
|
+
# Creates and extends an Arel <tt>Attribute</tt> representing the table's column with
|
10
|
+
# the given <tt>name</tt>.
|
11
|
+
#
|
12
|
+
# @param [String, Symbol] name The attribute name
|
13
|
+
#
|
14
|
+
# @note Please note that no exception is raised if no such column actually exists.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# User.where(User.attribute(:score) > 1000)
|
18
|
+
# # => SELECT "users".* FROM "users" WHERE ("users"."score" > 1000)
|
19
|
+
#
|
20
|
+
def attribute(name)
|
21
|
+
attribute = arel_table[name]
|
22
|
+
extend_expression(attribute)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates and extends an Arel <tt>SqlLiteral</tt> instance for the given <tt>expression</tt>,
|
26
|
+
# first converted to a string using <tt>to_s</tt>.
|
27
|
+
#
|
28
|
+
# @param [String, #to_s] expression Any SQL expression.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# def Circle.with_perimeter_smaller_than(perimeter)
|
32
|
+
# where sql(2 * Math::PI) * radius < perimeter
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Circle.with_perimeter_smaller_than(20)
|
36
|
+
# # => SELECT "circles".* FROM "circles" WHERE (6.283185307179586 * "circles"."radius" < 20)
|
37
|
+
#
|
38
|
+
def sql_literal(expression)
|
39
|
+
::Arel.sql(expression.to_s).tap do |literal|
|
40
|
+
extend_expression(literal)
|
41
|
+
extend_predicate(literal)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
alias_method :sql, :sql_literal
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module SexyScopes
|
2
|
+
module ActiveRecord
|
3
|
+
module DynamicMethods
|
4
|
+
# @!visibility private
|
5
|
+
def respond_to?(method_name, include_private = false) # :nodoc:
|
6
|
+
super || respond_to_missing?(method_name, include_private)
|
7
|
+
end
|
8
|
+
|
9
|
+
# # @!visibility private
|
10
|
+
def respond_to_missing?(method_name, include_private = false) # :nodoc:
|
11
|
+
Object.respond_to?(:respond_to_missing?) && super || sexy_scopes_has_attribute?(method_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
# Equivalent to calling {#attribute} with the missing method's <tt>name</tt> if the table
|
16
|
+
# has a column with that name.
|
17
|
+
#
|
18
|
+
# Delegates to superclass implementation otherwise, eventually raising <tt>NoMethodError</tt>.
|
19
|
+
#
|
20
|
+
# @see #attribute
|
21
|
+
#
|
22
|
+
# @note Due to the way this works, be careful not to use this syntactic sugar with existing
|
23
|
+
# <tt>ActiveRecord::Base</tt> methods (see last example).
|
24
|
+
#
|
25
|
+
# @raise [NoMethodError] if the table has no corresponding column
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# # Suppose the "users" table has an "email" column, then these are equivalent:
|
29
|
+
# User.email
|
30
|
+
# User.attribute(:email)
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# # Here is the previous example (from `attribute`) rewritten:
|
34
|
+
# User.where(User.score > 1000)
|
35
|
+
# # => SELECT "users".* FROM "users" WHERE ("users"."score" > 1000)
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# # Don't use it with existing `ActiveRecord::Base` methods, i.e. `name`:
|
39
|
+
# User.name # => "User"
|
40
|
+
# # In these cases you'll have to use `attribute` explicitely
|
41
|
+
# User.attribute(:name)
|
42
|
+
#
|
43
|
+
def method_missing(name, *args)
|
44
|
+
if sexy_scopes_has_attribute?(name)
|
45
|
+
sexy_scopes_define_attribute_method(name)
|
46
|
+
attribute(name)
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def sexy_scopes_define_attribute_method(name)
|
53
|
+
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
54
|
+
def self.#{name} # def self.username
|
55
|
+
attribute(:#{name}) # attribute(:username)
|
56
|
+
end # end
|
57
|
+
EVAL
|
58
|
+
end
|
59
|
+
|
60
|
+
def sexy_scopes_has_attribute?(attribute_name)
|
61
|
+
if equal?(::ActiveRecord::Base) || abstract_class? || !table_exists?
|
62
|
+
false
|
63
|
+
else
|
64
|
+
column_names.include?(attribute_name.to_s)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/sexy_scopes/arel.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module SexyScopes
|
2
2
|
module Arel
|
3
|
-
module
|
3
|
+
module MathMethods
|
4
4
|
def *(other)
|
5
5
|
extend_expression(super)
|
6
6
|
end
|
@@ -16,6 +16,10 @@ module SexyScopes
|
|
16
16
|
def /(other)
|
17
17
|
extend_expression(super)
|
18
18
|
end
|
19
|
+
|
20
|
+
def coerce(other)
|
21
|
+
[extend_expression(::Arel.sql(other.to_s)), self]
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
data/lib/sexy_scopes/version.rb
CHANGED
@@ -2,9 +2,17 @@ module SexyScopes
|
|
2
2
|
module Version
|
3
3
|
MAJOR = 0
|
4
4
|
MINOR = 5
|
5
|
-
TINY =
|
5
|
+
TINY = 1
|
6
6
|
|
7
7
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Allows {Version} to display ({to_s}) and behave ({to_str}) as a string
|
11
|
+
def to_str
|
12
|
+
STRING
|
13
|
+
end
|
14
|
+
alias_method :to_s, :to_str
|
15
|
+
end
|
8
16
|
end
|
9
17
|
|
10
18
|
VERSION = Version::STRING
|
data/lib/sexy_scopes/wrappers.rb
CHANGED
@@ -3,11 +3,11 @@ module SexyScopes
|
|
3
3
|
module Wrappers # :nodoc:
|
4
4
|
private
|
5
5
|
def extend_expression(expression)
|
6
|
-
expression.extend(
|
6
|
+
expression.extend(ExpressionWrappers)
|
7
7
|
end
|
8
8
|
|
9
9
|
def extend_predicate(predicate)
|
10
|
-
predicate.extend(
|
10
|
+
predicate.extend(PredicateWrappers)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
data/sexy_scopes.gemspec
CHANGED
@@ -20,10 +20,12 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_dependency 'activerecord', '~> 3.0'
|
21
21
|
|
22
22
|
gem.add_development_dependency 'bundler', '~> 1.0'
|
23
|
-
gem.add_development_dependency 'rake'
|
23
|
+
gem.add_development_dependency 'rake', '~> 0.9'
|
24
24
|
gem.add_development_dependency 'rails', '~> 3.0'
|
25
25
|
gem.add_development_dependency 'rspec', '~> 2.0'
|
26
|
-
gem.add_development_dependency 'sqlite3'
|
26
|
+
gem.add_development_dependency 'sqlite3', '~> 1.0'
|
27
|
+
gem.add_development_dependency 'redcarpet', '~> 2.2'
|
28
|
+
gem.add_development_dependency 'yard', '~> 0.8'
|
27
29
|
if RUBY_VERSION >= '1.9'
|
28
30
|
gem.add_development_dependency 'simplecov'
|
29
31
|
else
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SexyScopes::ActiveRecord::ClassMethods do
|
4
|
+
it "should extend ActiveRecord::Base" do
|
5
|
+
ActiveRecord::Base.should be_extended_by SexyScopes::ActiveRecord::ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ".attribute(name)" do
|
9
|
+
subject { User.attribute(:username) }
|
10
|
+
|
11
|
+
it "should return an Arel attribute for the given name" do
|
12
|
+
subject.should eql User.arel_table[:username]
|
13
|
+
end
|
14
|
+
|
15
|
+
it { should be_extended_by SexyScopes::ExpressionWrappers }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".sql_literal(expression)" do
|
19
|
+
subject { User.sql_literal('NOW()') }
|
20
|
+
|
21
|
+
it "should return an Arel literal for given expression" do
|
22
|
+
subject.should eql(::Arel.sql('NOW()'))
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be aliased as `sql`" do
|
26
|
+
SexyScopes::ActiveRecord::ClassMethods.instance_method(:sql).should ==
|
27
|
+
SexyScopes::ActiveRecord::ClassMethods.instance_method(:sql_literal)
|
28
|
+
end
|
29
|
+
|
30
|
+
it { should be_extended_by SexyScopes::ExpressionWrappers }
|
31
|
+
|
32
|
+
it { should be_extended_by SexyScopes::PredicateWrappers }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe SexyScopes::ActiveRecord::DynamicMethods do
|
37
|
+
before do
|
38
|
+
ActiveRecord::Migration.create_table :temp_users
|
39
|
+
ActiveRecord::Migration.add_column :temp_users, :username, :string
|
40
|
+
class ::TempUser < ActiveRecord::Base; end
|
41
|
+
end
|
42
|
+
|
43
|
+
after do
|
44
|
+
Object.send(:remove_const, :TempUser)
|
45
|
+
ActiveRecord::Migration.drop_table :temp_users
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should delegate to `attribute` when the method name is the name of an existing column" do
|
49
|
+
TempUser.should respond_to(:username)
|
50
|
+
TempUser.should_receive(:attribute).with(:username).once.and_return(:ok)
|
51
|
+
TempUser.username.should == :ok
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should define an attribute method to avoid repeated `method_missing` calls" do
|
55
|
+
TempUser.username
|
56
|
+
TempUser.should_not_receive(:method_missing)
|
57
|
+
TempUser.username
|
58
|
+
end
|
59
|
+
|
60
|
+
ruby_19 do
|
61
|
+
it "should return a Method object for an existing column" do
|
62
|
+
expect { TempUser.method(:username) }.to_not raise_error
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise NoMethodError for a non-existing column" do
|
67
|
+
TempUser.should_not respond_to(:foobar)
|
68
|
+
expect { TempUser.foobar }.to raise_error NoMethodError
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should not raise error when table doesn't exist" do
|
72
|
+
TempUser.table_name = "inexistent_users"
|
73
|
+
expect { TempUser.respond_to?(:username) }.to_not raise_error
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SexyScopes::Arel::BooleanMethods do
|
4
|
+
before do
|
5
|
+
@attribute = User.attribute(:score)
|
6
|
+
@predicate = @attribute < 1000
|
7
|
+
@predicate2 = @attribute >= 200
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".not" do
|
11
|
+
subject { @predicate.not }
|
12
|
+
|
13
|
+
it_behaves_like "a predicate method"
|
14
|
+
|
15
|
+
it { should convert_to_sql %{NOT ("users"."score" < 1000)} }
|
16
|
+
|
17
|
+
it "should be aliased as `~`" do
|
18
|
+
@predicate.method(:~).should == @predicate.method(:not)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".and(predicate)" do
|
23
|
+
subject { @predicate.and(@predicate2) }
|
24
|
+
|
25
|
+
it_behaves_like "a predicate method"
|
26
|
+
|
27
|
+
it { should convert_to_sql %{"users"."score" < 1000 AND "users"."score" >= 200} }
|
28
|
+
|
29
|
+
it "should be aliased as `&`" do
|
30
|
+
@predicate.method(:&).should == @predicate.method(:and)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe ".or(predicate)" do
|
35
|
+
subject { @predicate.or(@predicate2) }
|
36
|
+
|
37
|
+
it_behaves_like "a predicate method"
|
38
|
+
|
39
|
+
it { should convert_to_sql %{("users"."score" < 1000 OR "users"."score" >= 200)} }
|
40
|
+
|
41
|
+
it "should be aliased as `|`" do
|
42
|
+
@predicate.method(:|).should == @predicate.method(:or)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
RSpec::Matchers.define :convert_to_sql do |expected|
|
2
|
+
match do |actual|
|
3
|
+
actual.to_sql == expected
|
4
|
+
end
|
5
|
+
|
6
|
+
description do
|
7
|
+
"convert to the following SQL: #{expected}"
|
8
|
+
end
|
9
|
+
|
10
|
+
failure_message_for_should do |actual|
|
11
|
+
"expected generated SQL to be \n #{expected}\ngot\n #{actual.to_sql}"
|
12
|
+
end
|
13
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
shared_examples "an expression method" do
|
4
4
|
it "should return an Arel node" do
|
5
5
|
subject.class.name.should =~ /^Arel::/
|
6
6
|
end
|
7
7
|
|
8
|
-
it { should be_extended_by SexyScopes::
|
8
|
+
it { should be_extended_by SexyScopes::ExpressionWrappers }
|
9
9
|
end
|
10
10
|
|
11
|
-
describe SexyScopes::Arel::
|
11
|
+
describe SexyScopes::Arel::MathMethods do
|
12
12
|
before do
|
13
13
|
@attribute = User.attribute(:score)
|
14
14
|
end
|
@@ -44,4 +44,12 @@ describe SexyScopes::Arel::ExpressionMethods do
|
|
44
44
|
|
45
45
|
it { should convert_to_sql %{"users"."score" / 42.0} }
|
46
46
|
end
|
47
|
+
|
48
|
+
describe "type coercion" do
|
49
|
+
subject { 42.0 / @attribute }
|
50
|
+
|
51
|
+
it_behaves_like "an expression method"
|
52
|
+
|
53
|
+
it { should convert_to_sql %{42.0 / "users"."score"} }
|
54
|
+
end
|
47
55
|
end
|
@@ -1,12 +1,4 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
shared_examples "a predicate method" do
|
4
|
-
it "should return an Arel node" do
|
5
|
-
subject.class.name.should =~ /^Arel::/
|
6
|
-
end
|
7
|
-
|
8
|
-
it { should be_extended_by SexyScopes::Arel::PredicateWrappers }
|
9
|
-
end
|
1
|
+
require 'spec_helper'
|
10
2
|
|
11
3
|
describe SexyScopes::Arel::PredicateMethods do
|
12
4
|
before do
|
data/spec/spec_helper.rb
CHANGED
@@ -7,36 +7,22 @@ require 'rspec'
|
|
7
7
|
require 'active_record'
|
8
8
|
require 'sexy_scopes'
|
9
9
|
|
10
|
-
RSpec
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.extend Module.new {
|
12
|
+
def ruby_19
|
13
|
+
yield if RUBY_VERSION >= "1.9"
|
14
|
+
end
|
15
|
+
}
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
actual.to_sql == expected
|
20
|
-
end
|
21
|
-
|
22
|
-
description do
|
23
|
-
"convert to the following SQL: #{expected}"
|
24
|
-
end
|
25
|
-
|
26
|
-
failure_message_for_should do |actual|
|
27
|
-
"expected generated SQL to be \n #{expected}\ngot\n #{actual.to_sql}"
|
28
|
-
end
|
18
|
+
Dir.glob(File.join(File.dirname(__FILE__), '{fixtures,matchers}', '*')) do |file|
|
19
|
+
require file
|
29
20
|
end
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
ActiveRecord::Schema.define do
|
35
|
-
create_table :users do |t|
|
36
|
-
t.string :username
|
37
|
-
t.integer :score
|
22
|
+
shared_examples "a predicate method" do
|
23
|
+
it "should return an Arel node" do
|
24
|
+
subject.class.name.should =~ /^Arel::/
|
38
25
|
end
|
39
|
-
|
40
|
-
|
41
|
-
class User < ActiveRecord::Base
|
26
|
+
|
27
|
+
it { should be_extended_by SexyScopes::PredicateWrappers }
|
42
28
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sexy_scopes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -48,17 +48,17 @@ dependencies:
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
53
|
+
version: '0.9'
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
61
|
+
version: '0.9'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rails
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,17 +96,49 @@ dependencies:
|
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
|
-
- -
|
99
|
+
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '0'
|
101
|
+
version: '1.0'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
|
-
- -
|
107
|
+
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '0'
|
109
|
+
version: '1.0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: redcarpet
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '2.2'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '2.2'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: yard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0.8'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0.8'
|
110
142
|
- !ruby/object:Gem::Dependency
|
111
143
|
name: simplecov
|
112
144
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,18 +169,26 @@ files:
|
|
137
169
|
- Rakefile
|
138
170
|
- lib/sexy_scopes.rb
|
139
171
|
- lib/sexy_scopes/active_record.rb
|
172
|
+
- lib/sexy_scopes/active_record/class_methods.rb
|
173
|
+
- lib/sexy_scopes/active_record/dynamic_methods.rb
|
140
174
|
- lib/sexy_scopes/arel.rb
|
141
|
-
- lib/sexy_scopes/arel/
|
142
|
-
- lib/sexy_scopes/arel/
|
175
|
+
- lib/sexy_scopes/arel/boolean_methods.rb
|
176
|
+
- lib/sexy_scopes/arel/math_methods.rb
|
143
177
|
- lib/sexy_scopes/arel/predicate_methods.rb
|
144
|
-
- lib/sexy_scopes/
|
178
|
+
- lib/sexy_scopes/expression_wrappers.rb
|
179
|
+
- lib/sexy_scopes/predicate_wrappers.rb
|
145
180
|
- lib/sexy_scopes/railtie.rb
|
146
181
|
- lib/sexy_scopes/version.rb
|
147
182
|
- lib/sexy_scopes/wrappers.rb
|
148
183
|
- sexy_scopes.gemspec
|
149
|
-
- spec/
|
184
|
+
- spec/active_record_spec.rb
|
185
|
+
- spec/boolean_methods_spec.rb
|
186
|
+
- spec/fixtures/models.rb
|
187
|
+
- spec/fixtures/schema.rb
|
188
|
+
- spec/matchers/be_extended_by.rb
|
189
|
+
- spec/matchers/convert_to_sql.rb
|
190
|
+
- spec/math_methods_spec.rb
|
150
191
|
- spec/predicate_methods_spec.rb
|
151
|
-
- spec/sexy_scopes_spec.rb
|
152
192
|
- spec/spec_helper.rb
|
153
193
|
homepage: https://github.com/samleb/sexy_scopes
|
154
194
|
licenses:
|
@@ -163,18 +203,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
203
|
- - ! '>='
|
164
204
|
- !ruby/object:Gem::Version
|
165
205
|
version: '0'
|
166
|
-
segments:
|
167
|
-
- 0
|
168
|
-
hash: 953557397482339219
|
169
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
207
|
none: false
|
171
208
|
requirements:
|
172
209
|
- - ! '>='
|
173
210
|
- !ruby/object:Gem::Version
|
174
211
|
version: '0'
|
175
|
-
segments:
|
176
|
-
- 0
|
177
|
-
hash: 953557397482339219
|
178
212
|
requirements: []
|
179
213
|
rubyforge_project:
|
180
214
|
rubygems_version: 1.8.23
|
@@ -182,7 +216,13 @@ signing_key:
|
|
182
216
|
specification_version: 3
|
183
217
|
summary: Write beautiful and expressive ActiveRecord scopes without SQL.
|
184
218
|
test_files:
|
185
|
-
- spec/
|
219
|
+
- spec/active_record_spec.rb
|
220
|
+
- spec/boolean_methods_spec.rb
|
221
|
+
- spec/fixtures/models.rb
|
222
|
+
- spec/fixtures/schema.rb
|
223
|
+
- spec/matchers/be_extended_by.rb
|
224
|
+
- spec/matchers/convert_to_sql.rb
|
225
|
+
- spec/math_methods_spec.rb
|
186
226
|
- spec/predicate_methods_spec.rb
|
187
|
-
- spec/sexy_scopes_spec.rb
|
188
227
|
- spec/spec_helper.rb
|
228
|
+
has_rdoc:
|
data/spec/sexy_scopes_spec.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe SexyScopes::ActiveRecord do
|
4
|
-
it "should extend ActiveRecord::Base" do
|
5
|
-
ActiveRecord::Base.should be_extended_by SexyScopes::ActiveRecord
|
6
|
-
end
|
7
|
-
|
8
|
-
describe ".attribute(name)" do
|
9
|
-
subject { User.attribute(:username) }
|
10
|
-
|
11
|
-
it "should return an Arel attribute for the given name" do
|
12
|
-
subject.should eql User.arel_table[:username]
|
13
|
-
end
|
14
|
-
|
15
|
-
it { should be_extended_by SexyScopes::Arel::ExpressionWrappers }
|
16
|
-
end
|
17
|
-
|
18
|
-
describe ".sql_literal(expression)" do
|
19
|
-
subject { User.sql_literal('NOW()') }
|
20
|
-
|
21
|
-
it "should return an Arel literal for given expression" do
|
22
|
-
subject.should eql(::Arel.sql('NOW()'))
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should be aliased as `sql`" do
|
26
|
-
SexyScopes::ActiveRecord.instance_method(:sql).should ==
|
27
|
-
SexyScopes::ActiveRecord.instance_method(:sql_literal)
|
28
|
-
end
|
29
|
-
|
30
|
-
it { should be_extended_by SexyScopes::Arel::ExpressionWrappers }
|
31
|
-
|
32
|
-
it { should be_extended_by SexyScopes::Arel::PredicateWrappers }
|
33
|
-
end
|
34
|
-
|
35
|
-
context "dynamic method handling (method_missing/respond_to?)" do
|
36
|
-
it "should delegate to `attribute` when the method name is the name of an existing column" do
|
37
|
-
User.should respond_to(:username)
|
38
|
-
User.should_receive(:attribute).with(:username).once.and_return(:ok)
|
39
|
-
User.username.should == :ok
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should raise NoMethodError otherwise" do
|
43
|
-
User.should_not respond_to(:foobar)
|
44
|
-
lambda { User.foobar }.should raise_error NoMethodError
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|