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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -6
  3. data/README.md +56 -7
  4. data/lib/arel/visitors_extensions.rb +89 -0
  5. data/lib/sexy_scopes.rb +33 -10
  6. data/lib/sexy_scopes/active_record.rb +0 -1
  7. data/lib/sexy_scopes/active_record/class_methods.rb +5 -16
  8. data/lib/sexy_scopes/active_record/dynamic_methods.rb +26 -21
  9. data/lib/sexy_scopes/arel.rb +10 -28
  10. data/lib/sexy_scopes/arel/expression_methods.rb +9 -0
  11. data/lib/sexy_scopes/arel/math.rb +28 -0
  12. data/lib/sexy_scopes/arel/nodes/regexp_matches.rb +12 -0
  13. data/lib/sexy_scopes/arel/predicate_methods.rb +13 -38
  14. data/lib/sexy_scopes/arel/predications.rb +67 -0
  15. data/lib/sexy_scopes/arel/typecasting.rb +21 -0
  16. data/lib/sexy_scopes/version.rb +1 -1
  17. metadata +53 -50
  18. data/.gitignore +0 -4
  19. data/.travis.yml +0 -19
  20. data/Gemfile +0 -2
  21. data/Rakefile +0 -13
  22. data/ci/Gemfile.ar-edge +0 -8
  23. data/ci/Gemfile.ar3.1 +0 -8
  24. data/ci/Gemfile.ar3.2 +0 -8
  25. data/lib/sexy_scopes/arel/boolean_methods.rb +0 -20
  26. data/lib/sexy_scopes/arel/math_methods.rb +0 -25
  27. data/lib/sexy_scopes/expression_wrappers.rb +0 -7
  28. data/lib/sexy_scopes/predicate_wrappers.rb +0 -6
  29. data/lib/sexy_scopes/wrappers.rb +0 -13
  30. data/sexy_scopes.gemspec +0 -32
  31. data/spec/active_record_spec.rb +0 -73
  32. data/spec/boolean_methods_spec.rb +0 -45
  33. data/spec/fixtures/models.rb +0 -2
  34. data/spec/fixtures/schema.rb +0 -9
  35. data/spec/matchers/be_extended_by.rb +0 -6
  36. data/spec/matchers/convert_to_sql.rb +0 -13
  37. data/spec/math_methods_spec.rb +0 -55
  38. data/spec/predicate_methods_spec.rb +0 -38
  39. data/spec/spec_helper.rb +0 -28
data/ci/Gemfile.ar-edge DELETED
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'activerecord', :github => 'rails/rails', :branch => 'master'
4
-
5
- gem 'rake', '~> 0.9'
6
- gem 'rspec', '~> 2.0'
7
- gem 'sqlite3', '~> 1.0'
8
- gem 'coveralls', require: false
data/ci/Gemfile.ar3.1 DELETED
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'activerecord', '~> 3.1.0'
4
-
5
- gem 'rake', '~> 0.9'
6
- gem 'rspec', '~> 2.0'
7
- gem 'sqlite3', '~> 1.0'
8
- gem 'coveralls', require: false
data/ci/Gemfile.ar3.2 DELETED
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'activerecord', '~> 3.2.0'
4
-
5
- gem 'rake', '~> 0.9'
6
- gem 'rspec', '~> 2.0'
7
- gem 'sqlite3', '~> 1.0'
8
- gem 'coveralls', require: false
@@ -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
@@ -1,7 +0,0 @@
1
- module SexyScopes
2
- module ExpressionWrappers
3
- include Wrappers
4
- include Arel::PredicateMethods
5
- include Arel::MathMethods
6
- end
7
- end
@@ -1,6 +0,0 @@
1
- module SexyScopes
2
- module PredicateWrappers
3
- include Wrappers
4
- include Arel::BooleanMethods
5
- end
6
- end
@@ -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
@@ -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
@@ -1,2 +0,0 @@
1
- class User < ActiveRecord::Base
2
- end
@@ -1,9 +0,0 @@
1
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
2
-
3
- ActiveRecord::Schema.verbose = false
4
- ActiveRecord::Schema.define do
5
- create_table :users do |t|
6
- t.string :username
7
- t.integer :score
8
- end
9
- end
@@ -1,6 +0,0 @@
1
- RSpec::Matchers.define :be_extended_by do |expected|
2
- match do |actual|
3
- extended_modules = actual.singleton_class.included_modules
4
- extended_modules.include?(expected)
5
- end
6
- end
@@ -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
@@ -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