sakuramochi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", ">= 3.0.0"
4
+
5
+ group :development do
6
+ gem "sqlite3", "~> 1.3.4"
7
+ gem "rspec", "~> 2.6.0"
8
+ gem "bundler", "~> 1.0.0"
9
+ gem "jeweler", "~> 1.6.4"
10
+ gem "rcov", ">= 0"
11
+ end
12
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 mashiro
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # Sakuramochi
2
+
3
+ Sakuramochi is a minimal active record extensions for Rails3.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem 'sakuramochi', :git => 'git://github.com/mashiro/sakuramochi.git'
9
+ ```
10
+
11
+ ## Getting started
12
+
13
+ ```ruby
14
+ User.where(:name_contains => 'ai')
15
+ # => "SELECT \"users\".* FROM \"users\" WHERE (\"users\".\"name\" LIKE '%ai%')"
16
+
17
+ User.where(:name_contains_any => ['ru', 'ai'])
18
+ # => "SELECT \"users\".* FROM \"users\" WHERE ((\"users\".\"name\" LIKE '%ru%' OR \"users\".\"name\" LIKE '%ai%'))"
19
+
20
+ User.where(:name_contains_all => ['ru', 'ai'])
21
+ # => "SELECT \"users\".* FROM \"users\" WHERE ((\"users\".\"name\" LIKE '%ru%' AND \"users\".\"name\" LIKE '%ai%'))"
22
+ ```
23
+
24
+ ## Predicates
25
+
26
+ * contains
27
+ * starts_with, start_with
28
+ * ends_with, end_with
29
+ * in
30
+ * eq, equal, equals
31
+ * gt
32
+ * gte, gteq
33
+ * lt
34
+ * lte, lteq
35
+
36
+ ## Configration
37
+
38
+ ```ruby
39
+ Sakuramochi.configure do |config|
40
+ # simple
41
+ config.add :eq_amamiya,
42
+ :arel_predicate => :eq,
43
+ :converter => proc { |v| "amamiya #{v}" }
44
+
45
+ # advanced
46
+ config.add :surrounds_with, :surrounds_with_alias,
47
+ :arel_predicate => :matches,
48
+ :grouping => true,
49
+ :expand => false,
50
+ :converter => proc { |v| "#{v.first}%#{v.last}" },
51
+ :validator => proc { |v| true || v.is_a?(Enumerable) && v.to_a.size == 2 }
52
+ end
53
+
54
+ User.where(:name_eq_amamiya => 'rizumu')
55
+ # => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"name\" = 'amamiya rizumu'"
56
+
57
+ User.where(:name_surrounds_with => ["ama", "umu"])
58
+ # => "SELECT \"users\".* FROM \"users\" WHERE (\"users\".\"name\" LIKE 'ama%umu')"
59
+ ```
60
+
61
+ ## Copyright
62
+
63
+ Copyright (c) 2011 mashiro
64
+
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "sakuramochi"
18
+ gem.homepage = "http://github.com/mashiro/sakuramochi"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Minimal active record extension plugin for Rails 3}
21
+ gem.description = %Q{Minimal active record extension plugin for Rails 3}
22
+ gem.email = "mail@mashiro.org"
23
+ gem.authors = ["mashiro"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "sakuramochi #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ require 'sakuramochi/railtie'
@@ -0,0 +1,73 @@
1
+ require 'sakuramochi/predicate'
2
+
3
+ module Sakuramochi
4
+ def self.configure(&block)
5
+ yield @config ||= Sakuramochi::Configuration.new
6
+ end
7
+
8
+ def self.config
9
+ @config
10
+ end
11
+
12
+ class Configuration
13
+ attr_reader :predicates
14
+
15
+ def initialize
16
+ @predicates = {}
17
+ end
18
+
19
+ def add(*args)
20
+ options = args.extract_options!
21
+ options.reverse_merge!(:grouping => true)
22
+ args.flatten.each do |name|
23
+ name = name.to_s
24
+
25
+ suffixes = [nil]
26
+ suffixes += ['any', 'all'] if options[:grouping]
27
+
28
+ suffixes.each do |suffix|
29
+ predicate_name = [name, suffix].compact.join('_')
30
+ @predicates[predicate_name] = Predicate.new(options.merge({
31
+ :name => predicate_name,
32
+ :arel_predicate => [options[:arel_predicate], suffix].compact.join('_')
33
+ }))
34
+ end
35
+ end
36
+ end
37
+
38
+ def clear
39
+ @predicates.clear
40
+ end
41
+ end
42
+
43
+ configure do |config|
44
+ # default predicates
45
+ PREDICATES = {
46
+ :contains => [:contains],
47
+ :starts_with => [:starts_with, :start_with],
48
+ :ends_with => [:ends_with, :end_with],
49
+ :in => [:in],
50
+ :eq => [:eq, :equal, :equals],
51
+ :gt => [:gt],
52
+ :gte => [:gte, :gteq],
53
+ :lt => [:lt],
54
+ :lte => [:lte, :lteq],
55
+ }
56
+ _not = proc { |p| "not_#{p}" }
57
+
58
+ config.add PREDICATES[:contains], :arel_predicate => :matches, :converter => proc { |v| "%#{v}%" }
59
+ config.add PREDICATES[:contains].map(&_not), :arel_predicate => :does_not_match, :converter => proc { |v| "%#{v}%" }
60
+ config.add PREDICATES[:starts_with], :arel_predicate => :matches, :converter => proc { |v| "#{v}%" }
61
+ config.add PREDICATES[:starts_with].map(&_not), :arel_predicate => :does_not_match, :converter => proc { |v| "#{v}%" }
62
+ config.add PREDICATES[:ends_with], :arel_predicate => :matches, :converter => proc { |v| "%#{v}" }
63
+ config.add PREDICATES[:ends_with].map(&_not), :arel_predicate => :does_not_match, :converter => proc { |v| "%#{v}" }
64
+ config.add PREDICATES[:in], :arel_predicate => :in
65
+ config.add PREDICATES[:in].map(&_not), :arel_predicate => :not_in
66
+ config.add PREDICATES[:eq], :arel_predicate => :eq
67
+ config.add PREDICATES[:eq].map(&_not), :ne, :arel_predicate => :not_eq
68
+ config.add PREDICATES[:gt], :arel_predicate => :gt
69
+ config.add PREDICATES[:gte], :arel_predicate => :gteq
70
+ config.add PREDICATES[:lt], :arel_predicate => :lt
71
+ config.add PREDICATES[:lte], :arel_predicate => :lteq
72
+ end
73
+ end
@@ -0,0 +1,51 @@
1
+ require 'sakuramochi/config'
2
+
3
+ module Sakuramochi
4
+ class Predicate
5
+ attr_reader :name, :arel_predicate, :expand, :converter, :validator
6
+
7
+ def initialize(options = {})
8
+ options = options.reverse_merge(:expand => true)
9
+ @name = options[:name]
10
+ @arel_predicate = options[:arel_predicate]
11
+ @expand = options[:expand]
12
+ @converter = options[:converter]
13
+ @validator = options[:validator] || proc { |v| v.respond_to?(:empty?) ? !v.empty? : !v.nil? }
14
+ end
15
+
16
+ def convert(value)
17
+ return value unless @converter
18
+ if @expand
19
+ Predicate.as_a(value).map { |v| @converter.call(v) }
20
+ else
21
+ @converter.call(value)
22
+ end
23
+ end
24
+
25
+ def validate(value)
26
+ if @expand
27
+ Predicate.as_a(value).select { |v| @validator.call(v) }.any?
28
+ else
29
+ @validator.call(value)
30
+ end
31
+ end
32
+
33
+ def self.as_a(value)
34
+ value.is_a?(Enumerable) ? value.to_a : [value]
35
+ end
36
+
37
+ def self.names
38
+ Sakuramochi.config.predicates.keys
39
+ end
40
+
41
+ def self.names_by_decreasing_length
42
+ names.sort { |a, b| b.length <=> a.length }
43
+ end
44
+
45
+ def self.detect(attr)
46
+ attr_name = attr.to_s.dup
47
+ pred_name = names_by_decreasing_length.detect {|p| attr_name.sub!(/_#{p}$/, '')}
48
+ [attr_name, Sakuramochi.config.predicates[pred_name]]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,93 @@
1
+ require 'sakuramochi/predicate'
2
+ require 'active_support/concern'
3
+
4
+ module Sakuramochi
5
+ module PredicateBuilder
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ instance_eval do
10
+ alias :build_from_hash_without_predicate :build_from_hash
11
+ alias :build_from_hash :build_from_hash_with_predicate
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ def build_from_hash_with_predicate(engine, attributes, default_table)
17
+ predicates = attributes.map do |column, value|
18
+ table = default_table
19
+
20
+ if value.is_a?(Hash)
21
+ table = Arel::Table.new(column, engine)
22
+ build_from_hash(engine, value, table)
23
+ else
24
+ column = column.to_s
25
+
26
+ if column.include?('.')
27
+ table_name, column = column.split('.', 2)
28
+ table = Arel::Table.new(table_name, engine)
29
+ end
30
+
31
+ column_name, predicate = Predicate.detect(column.to_s)
32
+ attribute = table[column_name.to_sym]
33
+
34
+ if predicate
35
+ build_attribute_with_predicate(attribute, value, predicate)
36
+ else
37
+ build_attribute(attribute, value)
38
+ end
39
+ end
40
+ end
41
+
42
+ predicates.flatten.compact
43
+ end
44
+
45
+ def build_attribute_with_predicate(attribute, value, predicate)
46
+ if predicate.validate(value)
47
+ if predicate.converter
48
+ attribute.send(predicate.arel_predicate, predicate.convert(value))
49
+ else
50
+ relation = build_attribute(attribute, value)
51
+ attribute.send(predicate.arel_predicate, relation.right)
52
+ end
53
+ else
54
+ ''
55
+ end
56
+ end
57
+
58
+ def build_attribute(attribute, value)
59
+ case value
60
+ when ActiveRecord::Relation
61
+ value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
62
+ attribute.in(value.arel.ast)
63
+ when Array, ActiveRecord::Associations::CollectionProxy
64
+ values = value.to_a.map { |x|
65
+ x.is_a?(ActiveRecord::Base) ? x.id : x
66
+ }
67
+
68
+ if values.include?(nil)
69
+ values = values.compact
70
+ if values.empty?
71
+ attribute.eq nil
72
+ else
73
+ attribute.in(values.compact).or attribute.eq(nil)
74
+ end
75
+ else
76
+ attribute.in(values)
77
+ end
78
+
79
+ when Range, Arel::Relation
80
+ attribute.in(value)
81
+ when ActiveRecord::Base
82
+ attribute.eq(value.id)
83
+ when Class
84
+ # FIXME: I think we need to deprecate this behavior
85
+ attribute.eq(value.name)
86
+ else
87
+ attribute.eq(value)
88
+ end
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,18 @@
1
+ require 'rails'
2
+ require 'sakuramochi/config'
3
+ require 'sakuramochi/predicate'
4
+ require 'sakuramochi/predicate_builder'
5
+
6
+ module Sakuramochi
7
+ class Railtie < Rails::Railtie
8
+ initializer 'sakuramochi.initialize' do
9
+ ActiveSupport.on_load(:active_record) do
10
+ Railtie.setup
11
+ end
12
+ end
13
+
14
+ def self.setup
15
+ ActiveRecord::PredicateBuilder.send(:include, Sakuramochi::PredicateBuilder)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,72 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "sakuramochi"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["mashiro"]
12
+ s.date = "2011-10-13"
13
+ s.description = "Minimal active record extension plugin for Rails 3"
14
+ s.email = "mail@mashiro.org"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "LICENSE.txt",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/sakuramochi.rb",
28
+ "lib/sakuramochi/config.rb",
29
+ "lib/sakuramochi/predicate.rb",
30
+ "lib/sakuramochi/predicate_builder.rb",
31
+ "lib/sakuramochi/railtie.rb",
32
+ "sakuramochi.gemspec",
33
+ "spec/sakuramochi/config_spec.rb",
34
+ "spec/sakuramochi/predicate_builder_spec.rb",
35
+ "spec/sakuramochi/predicate_spec.rb",
36
+ "spec/spec_helper.rb",
37
+ "spec/support/schema.rb"
38
+ ]
39
+ s.homepage = "http://github.com/mashiro/sakuramochi"
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = "1.8.10"
43
+ s.summary = "Minimal active record extension plugin for Rails 3"
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<rails>, [">= 3.0.0"])
50
+ s.add_development_dependency(%q<sqlite3>, ["~> 1.3.4"])
51
+ s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
52
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
53
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
54
+ s.add_development_dependency(%q<rcov>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<rails>, [">= 3.0.0"])
57
+ s.add_dependency(%q<sqlite3>, ["~> 1.3.4"])
58
+ s.add_dependency(%q<rspec>, ["~> 2.6.0"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
61
+ s.add_dependency(%q<rcov>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<rails>, [">= 3.0.0"])
65
+ s.add_dependency(%q<sqlite3>, ["~> 1.3.4"])
66
+ s.add_dependency(%q<rspec>, ["~> 2.6.0"])
67
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
68
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
69
+ s.add_dependency(%q<rcov>, [">= 0"])
70
+ end
71
+ end
72
+
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sakuramochi::Configuration do
4
+ before do
5
+ Sakuramochi.configure do |config|
6
+ config.clear
7
+ @config = config
8
+ end
9
+ end
10
+ subject { @config }
11
+
12
+ describe '#configure' do
13
+ it { should be_an_instance_of Sakuramochi::Configuration }
14
+ its(:object_id) { should eq Sakuramochi.config.object_id }
15
+ end
16
+
17
+ describe '#clear' do
18
+ before do
19
+ @config.add :test1
20
+ @config.add :test2
21
+ @config.add :test3, :test4
22
+ @config.clear
23
+ end
24
+ subject { @config.predicates }
25
+
26
+ it { should be_empty }
27
+ end
28
+
29
+ describe '#add' do
30
+ before do
31
+ @config.add :test1, :grouping => true
32
+ @config.add :test2, :grouping => false
33
+ end
34
+ subject { @config.predicates }
35
+
36
+ it { should_not be_empty }
37
+
38
+ context 'with :test1, :grouping => true' do
39
+ it { should have_key 'test1' }
40
+ it { should have_key 'test1_any' }
41
+ it { should have_key 'test1_all' }
42
+ end
43
+
44
+ context 'with :test2, :grouping => false' do
45
+ it { should have_key 'test2' }
46
+ it { should_not have_key 'test2_any' }
47
+ it { should_not have_key 'test2_all' }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec::Matchers.define :be_match_all do |expected|
4
+ match do |actuals|
5
+ actuals.all? { |actual| !!(actual =~ expected) }
6
+ end
7
+ end
8
+
9
+ describe Sakuramochi::PredicateBuilder do
10
+ before(:all) do
11
+ @aira = User.create! :name => 'harune aira'
12
+ ['fresh fruit basket', 'munekyun taiken', 'heartful splash',
13
+ 'lovely rainbow', 'hirahira hiraku koi no hana', 'crystal splash'
14
+ ].each do |jump|
15
+ Status.create! :text => jump, :user => @aira
16
+ end
17
+
18
+ @rizumu = User.create! :name => 'amamiya rizumu'
19
+ ['heartful splash', 'colorful choco parade', 'fun fun heart dive',
20
+ 'stardust shower', 'happy macaron spin', 'pop\'n candy rocket'
21
+ ].each do |jump|
22
+ Status.create! :text => jump, :user => @rizumu
23
+ end
24
+ end
25
+
26
+ describe 'matches' do
27
+ before do
28
+ Sakuramochi.configure do |config|
29
+ config.clear
30
+ config.add :contains, :arel_predicate => :matches, :converter => proc { |v| "%#{v}%" }
31
+ end
32
+ @statuses = Status.where(key => value)
33
+ end
34
+ subject { @statuses }
35
+
36
+ shared_examples_for :never_match do
37
+ let(:value) { 'NEVER MATCH' }
38
+ it { should be_empty }
39
+ end
40
+
41
+ context 'contains' do
42
+ let(:key) { :text_contains }
43
+ context 'with "macaron"' do
44
+ let(:value) { 'macaron' }
45
+
46
+ it_should_behave_like :never_match
47
+ it { should have(1).items }
48
+ it { subject.map(&:text).should be_match_all /macaron/ }
49
+ end
50
+
51
+ context 'with "splash"' do
52
+ let(:value) { 'splash' }
53
+
54
+ it_should_behave_like :never_match
55
+ it { should have(3).items }
56
+ it { subject.map(&:text).should be_match_all /splash/ }
57
+ end
58
+ end
59
+
60
+ context 'contains_any' do
61
+ let(:key) { :text_contains_any }
62
+ context 'with ["heart", "splash"]' do
63
+ let(:value) { ['heart', 'splash'] }
64
+
65
+ it_should_behave_like :never_match
66
+ it { should have(4).items }
67
+ it { subject.map(&:text).should be_match_all /(heart|splash)/ }
68
+ end
69
+ end
70
+
71
+ context 'contains_all' do
72
+ let(:key) { :text_contains_all }
73
+ context 'with ["heart", "splash"]' do
74
+ let(:value) { ['heart', 'splash'] }
75
+
76
+ it_should_behave_like :never_match
77
+ it { should have(2).items }
78
+ it { subject.map(&:text).should be_match_all /heart/ }
79
+ it { subject.map(&:text).should be_match_all /splash/ }
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sakuramochi::Predicate do
4
+ describe '#convert' do
5
+ before do
6
+ @pred = Sakuramochi::Predicate.new :converter => converter
7
+ end
8
+
9
+ context 'default converter' do
10
+ let(:converter) { nil }
11
+ subject { @pred.convert(3) }
12
+
13
+ it { should eq 3 }
14
+ end
15
+
16
+ context 'custom converter' do
17
+ let(:converter) { proc { |v| v * v } }
18
+
19
+ context 'as unit' do
20
+ subject { @pred.convert(3) }
21
+ it { should eq [9] }
22
+ end
23
+
24
+ context 'as array' do
25
+ subject { @pred.convert([1,2,3]) }
26
+ it { should eq [1,4,9] }
27
+ end
28
+
29
+ context 'as range' do
30
+ subject { @pred.convert(1..3) }
31
+ it { should eq [1,4,9] }
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#validate' do
37
+ before do
38
+ @pred = Sakuramochi::Predicate.new :validator => validator
39
+ end
40
+
41
+ context 'default validator' do
42
+ let(:validator) { nil }
43
+
44
+ context 'with "value"' do
45
+ subject { @pred.validate('value') }
46
+ it { should be_true }
47
+ end
48
+
49
+ context 'with empty' do
50
+ subject { @pred.validate('') }
51
+ it { should be_false }
52
+ end
53
+
54
+ context 'with nil' do
55
+ subject { @pred.validate(nil) }
56
+ it { should be_false }
57
+ end
58
+ end
59
+
60
+ context 'custom validator: greater then 3' do
61
+ let(:validator) { proc { |v| v > 3 } }
62
+
63
+ context 'with 2' do
64
+ subject { @pred.validate(2) }
65
+ it { should be_false }
66
+ end
67
+
68
+ context 'with 4' do
69
+ subject { @pred.validate(4) }
70
+ it { should be_true }
71
+ end
72
+
73
+ context 'with (1..3)' do
74
+ subject { @pred.validate(1..3) }
75
+ it { should be_false }
76
+ end
77
+
78
+ context 'with (1..5)' do
79
+ subject { @pred.validate(1..5) }
80
+ it { should be_true }
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#detect' do
86
+ context 'config.add :test' do
87
+ before do
88
+ Sakuramochi.configure do |config|
89
+ config.add :test
90
+ end
91
+ end
92
+
93
+ context 'with :username_test' do
94
+ before { @name, @pred = Sakuramochi::Predicate.detect(:username_test) }
95
+ subject { {:name => @name, :pred => @pred } }
96
+ its([:name]) { should eq 'username' }
97
+ its([:pred]) { should be_instance_of Sakuramochi::Predicate }
98
+ end
99
+
100
+ context 'with :username_test2' do
101
+ before { @name, @pred = Sakuramochi::Predicate.detect(:username_test2) }
102
+ subject { {:name => @name, :pred => @pred } }
103
+ its([:name]) { should eq 'username_test2' }
104
+ its([:pred]) { should be_nil }
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'sakuramochi'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ config.before(:suite) do
12
+ CreateTestTables.up
13
+ Sakuramochi::Railtie.setup
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
4
+ ActiveRecord::Base.establish_connection('test')
5
+
6
+ class User < ActiveRecord::Base
7
+ has_many :statuses
8
+ end
9
+
10
+ class Status < ActiveRecord::Base
11
+ belongs_to :user
12
+ end
13
+
14
+ class CreateTestTables < ActiveRecord::Migration
15
+ def self.up
16
+ create_table :users do |t|
17
+ t.string :name
18
+ t.integer :age
19
+ end
20
+
21
+ create_table :statuses do |t|
22
+ t.references :user
23
+ t.string :text
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sakuramochi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - mashiro
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-13 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: &27264080 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *27264080
25
+ - !ruby/object:Gem::Dependency
26
+ name: sqlite3
27
+ requirement: &27263600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.3.4
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *27263600
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &27263040 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 2.6.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *27263040
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: &27262520 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *27262520
58
+ - !ruby/object:Gem::Dependency
59
+ name: jeweler
60
+ requirement: &27261880 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.6.4
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *27261880
69
+ - !ruby/object:Gem::Dependency
70
+ name: rcov
71
+ requirement: &27261220 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *27261220
80
+ description: Minimal active record extension plugin for Rails 3
81
+ email: mail@mashiro.org
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files:
85
+ - LICENSE.txt
86
+ - README.md
87
+ files:
88
+ - .document
89
+ - .rspec
90
+ - Gemfile
91
+ - LICENSE.txt
92
+ - README.md
93
+ - Rakefile
94
+ - VERSION
95
+ - lib/sakuramochi.rb
96
+ - lib/sakuramochi/config.rb
97
+ - lib/sakuramochi/predicate.rb
98
+ - lib/sakuramochi/predicate_builder.rb
99
+ - lib/sakuramochi/railtie.rb
100
+ - sakuramochi.gemspec
101
+ - spec/sakuramochi/config_spec.rb
102
+ - spec/sakuramochi/predicate_builder_spec.rb
103
+ - spec/sakuramochi/predicate_spec.rb
104
+ - spec/spec_helper.rb
105
+ - spec/support/schema.rb
106
+ homepage: http://github.com/mashiro/sakuramochi
107
+ licenses:
108
+ - MIT
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ segments:
120
+ - 0
121
+ hash: -4419155070054156166
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 1.8.10
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: Minimal active record extension plugin for Rails 3
134
+ test_files: []