sakuramochi 0.1.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.
@@ -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: []