sexy_scopes 0.6.0 → 0.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -6
- data/README.md +56 -7
- data/lib/arel/visitors_extensions.rb +89 -0
- data/lib/sexy_scopes.rb +33 -10
- data/lib/sexy_scopes/active_record.rb +0 -1
- data/lib/sexy_scopes/active_record/class_methods.rb +5 -16
- data/lib/sexy_scopes/active_record/dynamic_methods.rb +26 -21
- data/lib/sexy_scopes/arel.rb +10 -28
- data/lib/sexy_scopes/arel/expression_methods.rb +9 -0
- data/lib/sexy_scopes/arel/math.rb +28 -0
- data/lib/sexy_scopes/arel/nodes/regexp_matches.rb +12 -0
- data/lib/sexy_scopes/arel/predicate_methods.rb +13 -38
- data/lib/sexy_scopes/arel/predications.rb +67 -0
- data/lib/sexy_scopes/arel/typecasting.rb +21 -0
- data/lib/sexy_scopes/version.rb +1 -1
- metadata +53 -50
- data/.gitignore +0 -4
- data/.travis.yml +0 -19
- data/Gemfile +0 -2
- data/Rakefile +0 -13
- data/ci/Gemfile.ar-edge +0 -8
- data/ci/Gemfile.ar3.1 +0 -8
- data/ci/Gemfile.ar3.2 +0 -8
- data/lib/sexy_scopes/arel/boolean_methods.rb +0 -20
- data/lib/sexy_scopes/arel/math_methods.rb +0 -25
- data/lib/sexy_scopes/expression_wrappers.rb +0 -7
- data/lib/sexy_scopes/predicate_wrappers.rb +0 -6
- data/lib/sexy_scopes/wrappers.rb +0 -13
- data/sexy_scopes.gemspec +0 -32
- data/spec/active_record_spec.rb +0 -73
- data/spec/boolean_methods_spec.rb +0 -45
- data/spec/fixtures/models.rb +0 -2
- data/spec/fixtures/schema.rb +0 -9
- data/spec/matchers/be_extended_by.rb +0 -6
- data/spec/matchers/convert_to_sql.rb +0 -13
- data/spec/math_methods_spec.rb +0 -55
- data/spec/predicate_methods_spec.rb +0 -38
- data/spec/spec_helper.rb +0 -28
data/ci/Gemfile.ar-edge
DELETED
data/ci/Gemfile.ar3.1
DELETED
data/ci/Gemfile.ar3.2
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module SexyScopes
|
2
|
-
module Arel
|
3
|
-
module BooleanMethods
|
4
|
-
def not
|
5
|
-
extend_predicate(super)
|
6
|
-
end
|
7
|
-
alias ~ not
|
8
|
-
|
9
|
-
def or(other)
|
10
|
-
extend_predicate(super)
|
11
|
-
end
|
12
|
-
alias | or
|
13
|
-
|
14
|
-
def and(other)
|
15
|
-
extend_predicate(super)
|
16
|
-
end
|
17
|
-
alias & and
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module SexyScopes
|
2
|
-
module Arel
|
3
|
-
module MathMethods
|
4
|
-
def *(other)
|
5
|
-
extend_expression(super)
|
6
|
-
end
|
7
|
-
|
8
|
-
def +(other)
|
9
|
-
extend_expression(super)
|
10
|
-
end
|
11
|
-
|
12
|
-
def -(other)
|
13
|
-
extend_expression(super)
|
14
|
-
end
|
15
|
-
|
16
|
-
def /(other)
|
17
|
-
extend_expression(super)
|
18
|
-
end
|
19
|
-
|
20
|
-
def coerce(other)
|
21
|
-
[extend_expression(::Arel.sql(other.to_s)), self]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/sexy_scopes/wrappers.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
module SexyScopes
|
2
|
-
# @!visibility private
|
3
|
-
module Wrappers # :nodoc:
|
4
|
-
private
|
5
|
-
def extend_expression(expression)
|
6
|
-
expression.extend(ExpressionWrappers)
|
7
|
-
end
|
8
|
-
|
9
|
-
def extend_predicate(predicate)
|
10
|
-
predicate.extend(PredicateWrappers)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/sexy_scopes.gemspec
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
require File.expand_path('../lib/sexy_scopes/version', __FILE__)
|
3
|
-
|
4
|
-
Gem::Specification.new do |gem|
|
5
|
-
gem.name = 'sexy_scopes'
|
6
|
-
gem.version = SexyScopes::VERSION
|
7
|
-
|
8
|
-
gem.summary = %{Write beautiful and expressive ActiveRecord scopes without SQL.}
|
9
|
-
gem.description = %{Small DSL to create ActiveRecord (>= 3.1) attribute predicates without writing SQL.}
|
10
|
-
|
11
|
-
gem.authors = ['Samuel Lebeau']
|
12
|
-
gem.email = 'samuel.lebeau@gmail.com'
|
13
|
-
gem.homepage = 'https://github.com/samleb/sexy_scopes'
|
14
|
-
|
15
|
-
gem.files = `git ls-files`.split($/)
|
16
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
-
|
18
|
-
gem.licenses = ['MIT']
|
19
|
-
|
20
|
-
gem.required_ruby_version = '>= 1.9.2'
|
21
|
-
|
22
|
-
gem.add_dependency 'activerecord', '>= 3.1'
|
23
|
-
|
24
|
-
gem.add_development_dependency 'bundler', '~> 1.0'
|
25
|
-
gem.add_development_dependency 'rake', '>= 0.9'
|
26
|
-
gem.add_development_dependency 'rails', '~> 3.0'
|
27
|
-
gem.add_development_dependency 'rspec', '~> 2.0'
|
28
|
-
gem.add_development_dependency 'sqlite3', '~> 1.0'
|
29
|
-
gem.add_development_dependency 'redcarpet', '~> 2.2'
|
30
|
-
gem.add_development_dependency 'yard', '~> 0.8'
|
31
|
-
gem.add_development_dependency 'simplecov'
|
32
|
-
end
|
data/spec/active_record_spec.rb
DELETED
@@ -1,73 +0,0 @@
|
|
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
|
-
it "should return a Method object for an existing column" do
|
61
|
-
expect { TempUser.method(:username) }.to_not raise_error
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should raise NoMethodError for a non-existing column" do
|
65
|
-
TempUser.should_not respond_to(:foobar)
|
66
|
-
expect { TempUser.foobar }.to raise_error NoMethodError
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should not raise error when table doesn't exist" do
|
70
|
-
TempUser.table_name = "inexistent_users"
|
71
|
-
expect { TempUser.respond_to?(:username) }.to_not raise_error
|
72
|
-
end
|
73
|
-
end
|
@@ -1,45 +0,0 @@
|
|
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
|
data/spec/fixtures/models.rb
DELETED
data/spec/fixtures/schema.rb
DELETED
@@ -1,13 +0,0 @@
|
|
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
|
data/spec/math_methods_spec.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
shared_examples "an expression 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::ExpressionWrappers }
|
9
|
-
end
|
10
|
-
|
11
|
-
describe SexyScopes::Arel::MathMethods do
|
12
|
-
before do
|
13
|
-
@attribute = User.attribute(:score)
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "the method `*`" do
|
17
|
-
subject { @attribute * 42.0 }
|
18
|
-
|
19
|
-
it_behaves_like "an expression method"
|
20
|
-
|
21
|
-
it { should convert_to_sql %{"users"."score" * 42.0} }
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "the method `+`" do
|
25
|
-
subject { @attribute + 42.0 }
|
26
|
-
|
27
|
-
it_behaves_like "an expression method"
|
28
|
-
|
29
|
-
it { should convert_to_sql %{("users"."score" + 42.0)} }
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "the method `-`" do
|
33
|
-
subject { @attribute - 42.0 }
|
34
|
-
|
35
|
-
it_behaves_like "an expression method"
|
36
|
-
|
37
|
-
it { should convert_to_sql %{("users"."score" - 42.0)} }
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "the method `/`" do
|
41
|
-
subject { @attribute / 42.0 }
|
42
|
-
|
43
|
-
it_behaves_like "an expression method"
|
44
|
-
|
45
|
-
it { should convert_to_sql %{"users"."score" / 42.0} }
|
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
|
55
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SexyScopes::Arel::PredicateMethods do
|
4
|
-
before do
|
5
|
-
@attribute = User.attribute(:score)
|
6
|
-
end
|
7
|
-
|
8
|
-
METHODS = {
|
9
|
-
# Arel method => [ Ruby operator, SQL operator ]
|
10
|
-
:eq => [ '==', '= %s' ],
|
11
|
-
:in => [ nil, 'IN (%s)' ],
|
12
|
-
:matches => [ '=~', 'LIKE %s' ],
|
13
|
-
:does_not_match => [ '!~', 'NOT LIKE %s' ],
|
14
|
-
:gteq => '>=',
|
15
|
-
:gt => '>',
|
16
|
-
:lt => '<',
|
17
|
-
:lteq => '<=',
|
18
|
-
:not_eq => '!='
|
19
|
-
}
|
20
|
-
|
21
|
-
METHODS.each do |method, (operator, sql_operator)|
|
22
|
-
sql_operator ||= "#{operator} %s"
|
23
|
-
|
24
|
-
describe "the method `#{method}`" do
|
25
|
-
subject { @attribute.send(method, 42.0) }
|
26
|
-
|
27
|
-
it_behaves_like "a predicate method"
|
28
|
-
|
29
|
-
it { should convert_to_sql %{"users"."score" #{sql_operator % 42.0}} }
|
30
|
-
|
31
|
-
if operator
|
32
|
-
it "is aliased as `#{operator}`" do
|
33
|
-
described_class.instance_method(operator).should == described_class.instance_method(method)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
if ENV['TRAVIS']
|
2
|
-
require 'coveralls'
|
3
|
-
Coveralls.wear! do
|
4
|
-
# exclude gems bundled by Travis
|
5
|
-
add_filter 'ci/bundle'
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
if ENV['COVERAGE']
|
10
|
-
require 'simplecov'
|
11
|
-
SimpleCov.start
|
12
|
-
end
|
13
|
-
|
14
|
-
require 'rspec'
|
15
|
-
require 'active_record'
|
16
|
-
require 'sexy_scopes'
|
17
|
-
|
18
|
-
Dir.glob(File.join(File.dirname(__FILE__), '{fixtures,matchers}', '*')) do |file|
|
19
|
-
require file
|
20
|
-
end
|
21
|
-
|
22
|
-
shared_examples "a predicate method" do
|
23
|
-
it "should return an Arel node" do
|
24
|
-
subject.class.name.should =~ /^Arel::/
|
25
|
-
end
|
26
|
-
|
27
|
-
it { should be_extended_by SexyScopes::PredicateWrappers }
|
28
|
-
end
|