poor_man_search 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c93f4fed76ff17adb3df0be80611704d59aa29be
4
+ data.tar.gz: 8fc463375bbd69c6ef4f151cb25ff5608e89a9a3
5
+ SHA512:
6
+ metadata.gz: 6a34f887dff07995ac5823e2637692f3bdaa01f366a99589ba94568d866c95d09c8c57efa383d0315dee45574cf75b5bd4e8ee9d34cd748fac8f231090324787
7
+ data.tar.gz: 49541c24470958b6a1c3c1984715600067491e0432269243710d1300fe64860a69a3462b5f5e26caf1edc6caf2a650dba9f919dc7a7213834ad041f2c5ea4dcd
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ *#*
20
+ .DS_Store
21
+ .rvmrc
22
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in poor_man_search.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Yasuhiko Maeda
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,90 @@
1
+ # PoorManSearch
2
+
3
+ This module implement **Poor Man's Search Engin** to a active-record object.
4
+ > Poor Man's Search Engin is a SQL anti pattern that using LIKE with wildcards search..
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'poor_man_search'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ ## Usage
17
+
18
+ ### Example
19
+
20
+ A master table : users
21
+
22
+ | email | name | rank | registered_at |
23
+ |------------------|--------------|-----|-------------|
24
+ | taro@yamada.example.com | 山田太郎 | 1 | 2013-12-31 23:21:11 |
25
+ | hana@yamada.example.com | 山田華 | 3 | 2014-2-28 3:15:00 |
26
+ | chad@miller.example.com | Chad Miller | 1 | 2014-2-28 16:23:15 |
27
+
28
+
29
+ Configure like this.
30
+
31
+ ```ruby
32
+ class User < ActiveRecord::Base
33
+ extend PoorManSearch::Searchable
34
+ string_search :name, :email
35
+ number_search :rank
36
+ time_search :registered_at
37
+ end
38
+ ```
39
+
40
+ ### Search!
41
+
42
+ ```ruby
43
+ User.search "yamada"
44
+ ```
45
+
46
+ | email | name | rank | registered_at |
47
+ |------------------|--------------|-----|-------------|
48
+ | taro@yamada.example.com | 山田太郎 | 1 | 2013-12-31 23:21:11 |
49
+ | hana@yamada.example.com | 山田華 | 3 | 2014-2-28 3:15:00 |
50
+
51
+ ---
52
+
53
+ ```ruby
54
+ User.search "yamada 太郎"
55
+ ```
56
+
57
+ | email | name | rank | registered_at |
58
+ |------------------|--------------|-----|-------------|
59
+ | taro@yamada.example.com | 山田太郎 | 1 | 2013-12-31 23:21:11 |
60
+
61
+ ---
62
+
63
+ ```ruby
64
+ User.search "1"
65
+ ```
66
+
67
+ | email | name | rank | registered_at |
68
+ |------------------|--------------|-----|-------------|
69
+ | taro@yamada.example.com | 山田太郎 | 1 | 2013-12-31 23:21:11 |
70
+ | chad@miller.example.com | Chad Miller | 1 | 2014-2-28 16:23:15 |
71
+
72
+ ---
73
+
74
+ ```ruby
75
+ User.search "2/28"
76
+ ```
77
+
78
+ | email | name | rank | registered_at |
79
+ |------------------|--------------|-----|-------------|
80
+ | hana@yamada.example.com | 山田華 | 3 | 2014-2-28 3:15:00 |
81
+ | chad@miller.example.com | Chad Miller | 1 | 2014-2-28 16:23:15 |
82
+
83
+
84
+ ## Contributing
85
+
86
+ 1. Fork it
87
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
88
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
89
+ 4. Push to the branch (`git push origin my-new-feature`)
90
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ require "poor_man_search/version"
2
+ require "poor_man_search/criteria"
3
+ require "poor_man_search/searchable"
@@ -0,0 +1,60 @@
1
+ module PoorManSearch
2
+ class Criteria
3
+ attr_accessor :strings, :stringables, :numbers, :times, :time_range
4
+
5
+ @s = nil
6
+
7
+ def initialize irregularity = nil
8
+ parse irregularity
9
+ end
10
+
11
+ private
12
+
13
+ def parse irregularity
14
+ self.strings = []
15
+ self.stringables = []
16
+ self.numbers = []
17
+ self.times = []
18
+ self.time_range = []
19
+
20
+ words = irregularity.to_s.gsub / /, " "
21
+ words.split(" ").each do |word|
22
+ num = number_parse word
23
+ time = time_parse word
24
+
25
+ self.strings << word unless num || time
26
+ self.numbers << num if num
27
+ self.times << time if time
28
+ end
29
+
30
+ self.time_range = [self.times.min, self.times.max] if self.times.count >= 2
31
+ end
32
+
33
+ DATE_FORMATS = {:date_hour_minute => [/^\d+(\/)\d+(-)\d+(:)\d+$/, '%m/%d-%H:%M'],
34
+ :date_hour => [/^\d+(\/)\d+(-)\d+$/, '%m/%d-%H'],
35
+ :date => [/^\d+(\/)\d+$/, '%m/%d'],
36
+ :time => [/^\d+(:)\d+$/, '%H:%M']}
37
+
38
+ def time_parse ss
39
+ date = parse_format(ss, DATE_FORMATS[:date_hour_minute])
40
+ date ||= parse_format(ss, DATE_FORMATS[:date_hour])
41
+ date ||= parse_format(ss, DATE_FORMATS[:date])
42
+ date ||= parse_format(ss, DATE_FORMATS[:time])
43
+ return date
44
+ rescue Exception
45
+ return nil
46
+ end
47
+
48
+ def parse_format(ss, format)
49
+ return nil unless ss=~ format[0]
50
+ return Time.strptime(ss, format[1])
51
+ rescue Exception
52
+ return nil
53
+ end
54
+
55
+ def number_parse s
56
+ return nil unless s =~ /^(|-)\d+(|\.(|\d+))$/
57
+ return BigDecimal.new s
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,105 @@
1
+ module PoorManSearch
2
+ module Searchable
3
+ def string_search *fields
4
+ @string_fields = fields
5
+ end
6
+
7
+ def number_search *fields
8
+ @number_fields = fields
9
+ end
10
+
11
+ def time_search *fields
12
+ @time_fields = fields
13
+ end
14
+
15
+ def time_range *fields
16
+ @time_fields = fields
17
+ end
18
+
19
+ def search key_words_string
20
+ criteria = Criteria.new key_words_string
21
+ t = self.arel_table
22
+
23
+ search_scope = scoped
24
+ clauses = string_clauses(t, criteria)
25
+ clauses << number_clause(t, criteria)
26
+ clauses << time_clause(t, criteria)
27
+
28
+ clauses.compact.each{|clause|
29
+ search_scope = search_scope.where(clause)
30
+ }
31
+ search_scope
32
+ end
33
+
34
+ def associative_search key_words_string, *associations
35
+ ids = search(key_words_string).select("#{self.table_name}.id")
36
+ ids += associations.collect{|as|
37
+ scoped.includes(as).merge(asociation_class(as).search(key_words_string)).select("#{self.table_name}.id")
38
+ }.flatten
39
+ where(:id => ids.uniq)
40
+ end
41
+
42
+ private
43
+
44
+ def asociation_class as_sym
45
+ _as = as_sym
46
+ while(_as.is_a? Hash) do
47
+ _as = _as.values.first
48
+ end
49
+ _as.to_s.singularize.classify.constantize
50
+ end
51
+
52
+ def string_clauses(t, criteria)
53
+ return [] if @string_fields.blank?
54
+ criteria.strings.collect do |word|
55
+ v = "%#{word}%"
56
+ clause = nil
57
+
58
+ @string_fields.collect{|f|
59
+ t[f].matches(v)
60
+ }.each{|t_node|
61
+ clause = clause.or(t_node) rescue t_node
62
+ }
63
+ clause
64
+ end
65
+ end
66
+
67
+ def number_clause(t, criteria)
68
+ return nil if @number_fields.blank?
69
+ clause = nil
70
+ criteria.numbers.collect do |value|
71
+ @number_fields.collect{|f|
72
+ t[f].eq(value)
73
+ }.each{|t_node|
74
+ clause = clause.or(t_node) rescue t_node
75
+ }
76
+ end
77
+ clause
78
+ end
79
+
80
+ def time_clause(t, criteria)
81
+ return nil if @time_fields.blank?
82
+ clause = nil
83
+ criteria.times.each do |value|
84
+ @time_fields.each{|f|
85
+ find_by_time(t, value).each{|t_node|
86
+ clause = clause.or(t_node) rescue t_node
87
+ }
88
+ }
89
+ end
90
+ clause
91
+ end
92
+
93
+ def find_by_time(table, time)
94
+ return fetch_from_time_range(table, time, time+59.seconds) if (time.hour > 0 && time.min > 0)
95
+ return fetch_from_time_range(table, time.beginning_of_hour, time.end_of_hour) if (time.hour > 0)
96
+ return fetch_from_time_range(table, time.beginning_of_day, time.end_of_day)
97
+ end
98
+
99
+ def fetch_from_time_range(table, start_time, end_time)
100
+ @time_fields.collect{|f|
101
+ table[f].gteq(start_time).and(table[f].lteq(end_time))
102
+ }
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,3 @@
1
+ module PoorManSearch
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'poor_man_search/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "poor_man_search"
8
+ spec.version = PoorManSearch::VERSION
9
+ spec.authors = ["Yasuhiko Maeda"]
10
+ spec.email = ["y.maeda@dongoon.jp"]
11
+ spec.description = %q{Poor man's search engine module for Rails3 (Arel)}
12
+ spec.summary = %q{Poor man's search engine module for Rails3 (Arel)}
13
+ spec.homepage = "https://github.com/dongoon/poor_man_search"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "simplecov"
26
+ spec.add_development_dependency "sqlite3-ruby"
27
+ spec.add_development_dependency "database_cleaner"
28
+
29
+ spec.add_runtime_dependency "activerecord", "~> 3.2", ">= 3.0.0"
30
+ spec.add_runtime_dependency "arel", ">= 3.0.0"
31
+ end
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+
3
+ describe PoorManSearch::Criteria do
4
+ describe "::new" do
5
+ it "should receive single params" do
6
+ proc{PoorManSearch::Criteria.new("abc")}.should_not raise_error
7
+ end
8
+
9
+ it "should receive single params nilable" do
10
+ proc{PoorManSearch::Criteria.new}.should_not raise_error
11
+ proc{PoorManSearch::Criteria.new(nil)}.should_not raise_error
12
+ end
13
+
14
+ it "should not receive multi params" do
15
+ proc{PoorManSearch::Criteria.new("a", "b")}.should raise_error(ArgumentError)
16
+ end
17
+ end
18
+
19
+ describe "parse" do
20
+
21
+ describe "time_parse" do
22
+ let(:c){PoorManSearch::Criteria.new}
23
+ context "time parsable string" do
24
+ it "should return Time parsed object" do
25
+ [
26
+ "2/1",
27
+ "12/31-12:54",
28
+ "11:30",
29
+ ].each{|s|
30
+ c.send(:time_parse, s).should == Time.parse(s)
31
+ }
32
+ end
33
+ end
34
+
35
+ context "NOT time parsable string" do
36
+ it "should return nil" do
37
+ [
38
+ "hoge",
39
+ "1231",
40
+ "13/9",
41
+ ].each{|s|
42
+ c.send(:time_parse, s).should be_nil
43
+ }
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "number_parse" do
49
+ let(:c){PoorManSearch::Criteria.new}
50
+
51
+ context "number parsable string" do
52
+ it "should return BigDecimal object" do
53
+ [
54
+ "1",
55
+ "134",
56
+ "12.001",
57
+ "11.",
58
+ "-1.5",
59
+ ].each{|s|
60
+ c.send(:number_parse, s).should == BigDecimal.new(s)
61
+ }
62
+ end
63
+ end
64
+
65
+ context "NOT number parsable string" do
66
+ it "should return nil" do
67
+ [
68
+ "hoge",
69
+ "12/31",
70
+ "1.3.9",
71
+ "1..3",
72
+ ].each{|s|
73
+ c.send(:number_parse, s).should be_nil
74
+ }
75
+ end
76
+ end
77
+ end
78
+
79
+ context "empty params" do
80
+ let(:criteria){
81
+ PoorManSearch::Criteria.new(@search_string)
82
+ }
83
+
84
+ before {
85
+ criteria.strings = %w(hoge fuga)
86
+ criteria.stringables = %w(1/2 2/2)
87
+ criteria.numbers = [1, 2, 3]
88
+ criteria.times = [Time.now, 1.day.ago, 2.day.since]
89
+ criteria.time_range = [1.day.ago, Date.today]
90
+ }
91
+ it "should not raise error" do
92
+ proc{
93
+ criteria.send :parse, nil
94
+ }.should_not raise_error
95
+ end
96
+
97
+ it "should make properties to nil" do
98
+ criteria.strings.count.should == 2
99
+ criteria.send :parse, nil
100
+ criteria.strings.should == []
101
+ criteria.stringables.should == []
102
+ criteria.times.should == []
103
+ criteria.time_range.should == []
104
+ end
105
+ end
106
+
107
+ describe "strings" do
108
+ context "single word" do
109
+ it "should be [sing_word]" do
110
+ criteria = PoorManSearch::Criteria.new "あれ"
111
+ criteria.strings.count.should == 1
112
+ criteria.strings.should == ["あれ"]
113
+ end
114
+ end
115
+
116
+ context "multi words" do
117
+ it "should be [word1, word2]" do
118
+ criteria = PoorManSearch::Criteria.new " あれ hoge\tどれ\nmore a "
119
+ criteria.strings.count.should == 5
120
+ criteria.strings.should == ["あれ", "hoge", "どれ", "more", "a"]
121
+ end
122
+ end
123
+
124
+ context "with word be parsable other type" do
125
+ it "should be [word(!number & !time)..]" do
126
+ criteria = PoorManSearch::Criteria.new "あれ 1/2 どれ 123"
127
+ criteria.strings.count.should == 2
128
+ criteria.strings.should == ["あれ", "どれ"]
129
+ end
130
+ end
131
+ end
132
+
133
+ describe "numbers" do
134
+ context "with numberable words" do
135
+ it "should be [number..]" do
136
+ criteria = PoorManSearch::Criteria.new "hoge 123 1.02 fuga 2"
137
+ criteria.numbers.count.should == 3
138
+ criteria.numbers.should == [
139
+ BigDecimal.new("123"),
140
+ BigDecimal.new("1.02"),
141
+ BigDecimal.new("2")
142
+ ]
143
+ end
144
+ end
145
+
146
+ context "without numberable word" do
147
+ it "should be empty array" do
148
+ criteria = PoorManSearch::Criteria.new "hoge 123/3 1.r fuga "
149
+ criteria.numbers.should == []
150
+ end
151
+ end
152
+ end
153
+
154
+ describe "times" do
155
+ context "with timable words" do
156
+ it "should be [time..]" do
157
+ criteria = PoorManSearch::Criteria.new "hoge 1/2 2/10-10:13 fuga 2/2"
158
+ criteria.times.count.should == 3
159
+ criteria.times.should == [
160
+ Time.parse("1/2"),
161
+ Time.parse("2/10-10:13"),
162
+ Time.parse("2/2")
163
+ ]
164
+ end
165
+ end
166
+
167
+ context "without timable word" do
168
+ it "should be empty array" do
169
+ criteria = PoorManSearch::Criteria.new "hoge 1233 1.r fuga "
170
+ criteria.times.should == []
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "time_range" do
176
+ context "with two or more timable words" do
177
+ it "should be [min, max]" do
178
+ criteria = PoorManSearch::Criteria.new "2/2 1/10 hoge 1/15"
179
+ criteria.time_range.count.should == 2
180
+ criteria.time_range.should == [
181
+ Time.parse("1/10"),
182
+ Time.parse("2/2")
183
+ ]
184
+ end
185
+ end
186
+
187
+ context "with one or less timable words" do
188
+ it "should be empty array" do
189
+ criteria = PoorManSearch::Criteria.new "2/2"
190
+ criteria.time_range.count.should == 0
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe PoorManSearch do
4
+ it 'should have a version number' do
5
+ PoorManSearch::VERSION.should_not be_nil
6
+ end
7
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ # see test_models.rb
4
+ class User
5
+ extend PoorManSearch::Searchable
6
+ string_search :name, :email
7
+ number_search :rank
8
+ time_search :registered_at
9
+ end
10
+
11
+ class Comment
12
+ extend PoorManSearch::Searchable
13
+ string_search :said
14
+ number_search :count
15
+ end
16
+
17
+ describe PoorManSearch::Searchable do
18
+ let(:user1){ User.create(email: "taro@yamada.example.com",
19
+ name: "山田太郎",
20
+ rank: 1,
21
+ registered_at: Time.parse('2013-12-31 23:21:11')) }
22
+
23
+ let(:user2){ User.create(email: "hana@yamada.example.com",
24
+ name: "山田華",
25
+ rank: 3,
26
+ registered_at: Time.parse('2014-2-28 3:15:00')) }
27
+
28
+ let(:user3){ User.create(email: "chad@miller.example.com",
29
+ name: "Chad Miller",
30
+ rank: 1,
31
+ registered_at: Time.parse('2014-2-28 16:23:15')) }
32
+
33
+ let(:users){ [user1, user2, user3] }
34
+ before{ users }
35
+
36
+ describe "::search" do
37
+
38
+ subject{ User.search search_string }
39
+
40
+ shared_examples_for "User#search" do
41
+ it "should get records match search string" do
42
+ subject.count.should == expected_hits.count
43
+ expected_hits.each{|user| subject.map(&:email).should be_include user.email }
44
+ end
45
+ end
46
+
47
+ describe "string field search" do
48
+ context "single word" do
49
+ let(:search_string){ "yamada" }
50
+ let(:expected_hits){ [user1, user2] }
51
+ it_behaves_like "User#search"
52
+ end
53
+
54
+ context "multiple words" do
55
+ let(:search_string){ "yamada 太郎" }
56
+ let(:expected_hits){ [user1] }
57
+ it_behaves_like "User#search"
58
+ end
59
+ end
60
+
61
+ describe "number field search" do
62
+ let(:search_string){ "1" }
63
+ let(:expected_hits){ [user1, user3] }
64
+ it_behaves_like "User#search"
65
+ end
66
+
67
+ describe "time field search" do
68
+ context "date" do
69
+ let(:search_string){ "2/28" }
70
+ let(:expected_hits){ [user2, user3] }
71
+ it_behaves_like "User#search"
72
+ end
73
+
74
+ context "datetime" do
75
+ let(:search_string){ "2/28-3:15" }
76
+ let(:expected_hits){ [user2] }
77
+ it_behaves_like "User#search"
78
+ end
79
+ end
80
+
81
+ describe "types mix" do
82
+ let(:search_string){ "example.com 3" }
83
+ let(:expected_hits){ [user2] }
84
+ it_behaves_like "User#search"
85
+ end
86
+ end
87
+
88
+ describe "::associative_search" do
89
+ before{
90
+ user1.say "どうもどうも"
91
+ user2.say "あら遅いじゃない"
92
+ user3.say "now?"
93
+ user1.say "なんだって!?"
94
+ user2.say "どうどう"
95
+ user1.say "馬?"
96
+ }
97
+
98
+ subject{ User.associative_search search_string, :comments }
99
+
100
+ shared_examples_for "User#associative_search" do
101
+ it "should get records match search string" do
102
+ subject.count.should == expected_hits.count
103
+ expected_hits.each{|user| subject.map(&:email).should be_include user.email }
104
+ end
105
+ end
106
+
107
+ context "associate entity search case1" do
108
+ let(:search_string){ "どう" }
109
+ let(:expected_hits){ [user1, user2] }
110
+ it_behaves_like "User#associative_search"
111
+ end
112
+
113
+ context "associate entity search case2" do
114
+ let(:search_string){ "?" }
115
+ let(:expected_hits){ [user1, user3] }
116
+ it_behaves_like "User#associative_search"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'rspec'
3
+ require 'poor_man_search'
4
+
5
+ if ENV['COVERAGE']
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ add_filter '/spec/'
9
+ add_filter '/vendor/'
10
+ end
11
+ end
12
+
13
+ # load spec/support/**/*.rb
14
+ Dir["#{File.dirname(__FILE__)}/support/*.rb"].each {|f| require f}
@@ -0,0 +1,15 @@
1
+ require 'database_cleaner'
2
+
3
+ DatabaseCleaner[:active_record].strategy = :transaction if defined? ActiveRecord
4
+
5
+ RSpec.configure do |config|
6
+ config.before :suite do
7
+ DatabaseCleaner.clean_with :truncation
8
+ end
9
+ config.before :each do
10
+ DatabaseCleaner.start
11
+ end
12
+ config.after :each do
13
+ DatabaseCleaner.clean
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ require 'active_record'
2
+ ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ':memory:')
3
+
4
+ class CreateTestTables < ActiveRecord::Migration
5
+ def self.up
6
+ create_table :users do |t|
7
+ t.string :email
8
+ t.string :name
9
+ t.integer :rank
10
+ t.datetime :registered_at
11
+ end
12
+
13
+ create_table :comments do |t|
14
+ t.integer :user_id
15
+ t.integer :count
16
+ t.string :said
17
+ end
18
+ end
19
+ end
20
+
21
+ ActiveRecord::Migration.verbose = false
22
+ CreateTestTables.up
23
+
24
+
25
+ class User < ActiveRecord::Base
26
+ has_many :comments
27
+
28
+ def say comment
29
+ comments.create(count: comments.count + 1, said: comment)
30
+ end
31
+ end
32
+
33
+ class Comment < ActiveRecord::Base
34
+ belongs_to :user
35
+ end
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poor_man_search
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Yasuhiko Maeda
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3-ruby
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: database_cleaner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '3.2'
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: 3.0.0
107
+ type: :runtime
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ~>
112
+ - !ruby/object:Gem::Version
113
+ version: '3.2'
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: 3.0.0
117
+ - !ruby/object:Gem::Dependency
118
+ name: arel
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: 3.0.0
124
+ type: :runtime
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: 3.0.0
131
+ description: Poor man's search engine module for Rails3 (Arel)
132
+ email:
133
+ - y.maeda@dongoon.jp
134
+ executables: []
135
+ extensions: []
136
+ extra_rdoc_files: []
137
+ files:
138
+ - .gitignore
139
+ - .rspec
140
+ - .travis.yml
141
+ - Gemfile
142
+ - LICENSE.txt
143
+ - README.md
144
+ - Rakefile
145
+ - lib/poor_man_search.rb
146
+ - lib/poor_man_search/criteria.rb
147
+ - lib/poor_man_search/searchable.rb
148
+ - lib/poor_man_search/version.rb
149
+ - poor_man_search.gemspec
150
+ - spec/criteria_spec.rb
151
+ - spec/poor_man_search_spec.rb
152
+ - spec/searchable_spec.rb
153
+ - spec/spec_helper.rb
154
+ - spec/support/database_cleaner.rb
155
+ - spec/support/test_models.rb
156
+ homepage: https://github.com/dongoon/poor_man_search
157
+ licenses:
158
+ - MIT
159
+ metadata: {}
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - '>='
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubyforge_project:
176
+ rubygems_version: 2.2.2
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: Poor man's search engine module for Rails3 (Arel)
180
+ test_files:
181
+ - spec/criteria_spec.rb
182
+ - spec/poor_man_search_spec.rb
183
+ - spec/searchable_spec.rb
184
+ - spec/spec_helper.rb
185
+ - spec/support/database_cleaner.rb
186
+ - spec/support/test_models.rb