sexy_scopes 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|