texticle 2.0.2 → 2.0.3
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.
- data/CHANGELOG.rdoc +20 -1
- data/README.rdoc +13 -0
- data/Rakefile +32 -1
- data/lib/texticle.rb +27 -18
- data/lib/texticle/searchable.rb +2 -2
- data/spec/texticle/searchable_spec.rb +16 -12
- data/spec/texticle_spec.rb +86 -38
- metadata +35 -15
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
== 2.0.3
|
2
|
+
|
3
|
+
* 1 new feature
|
4
|
+
|
5
|
+
* Allow searching through relations. Model.join(:relation).search(:relation => {:column => "query"})
|
6
|
+
works, and reduces the need for multi-model tables. Huge thanks to Ben Hamill for the pull request.
|
7
|
+
* Allow searching through all model columns irrespective of the column's type; we cast all columns to text
|
8
|
+
in the search query. Performance may degrade when searching through anything but a string column.
|
9
|
+
|
10
|
+
* 2 bugfixes
|
11
|
+
|
12
|
+
* Fix exceptions when adding Texticle to a table-less model.
|
13
|
+
* Column names in a search query are now scoped to the current table.
|
14
|
+
|
15
|
+
* 1 dev improvement
|
16
|
+
|
17
|
+
* Running `rake` from the project root will setup the test environment by creating a test database
|
18
|
+
and running the necessary migrations. `rake` can also be used to run all the project tests.
|
19
|
+
|
1
20
|
== 2.0.2
|
2
21
|
|
3
22
|
* 1 bugfix
|
@@ -25,7 +44,7 @@
|
|
25
44
|
|
26
45
|
require 'texticle/searchable'
|
27
46
|
class Game
|
28
|
-
|
47
|
+
extend Searchable(:title)
|
29
48
|
end
|
30
49
|
|
31
50
|
This also allows Texticle use in Rails without having #search available to all models:
|
data/README.rdoc
CHANGED
@@ -38,6 +38,19 @@ Your models now have access to the search method:
|
|
38
38
|
Game.search_by_title_and_system('Final Fantasy', 'PS2')
|
39
39
|
Game.search_by_title_or_system('Final Fantasy, 'PS3')
|
40
40
|
|
41
|
+
=== Creating Indexes for Super Speed
|
42
|
+
You can have Postgresql use an index for the full-text search. To declare a full-text index, in a
|
43
|
+
migration add code like the following:
|
44
|
+
|
45
|
+
execute "
|
46
|
+
create index on email_logs using gin(to_tsvector('english', subject));
|
47
|
+
create index on email_logs using gin(to_tsvector('english', email_address));"
|
48
|
+
|
49
|
+
In the above example, the table email_logs has two text columns that we search against, subject and email_address.
|
50
|
+
You will need to add an index for every text/string column you query against, or else Postgresql will revert to a
|
51
|
+
full table scan instead of using the indexes.
|
52
|
+
|
53
|
+
|
41
54
|
== REQUIREMENTS:
|
42
55
|
|
43
56
|
* ActiveRecord
|
data/Rakefile
CHANGED
@@ -5,27 +5,58 @@ require 'pg'
|
|
5
5
|
require 'active_record'
|
6
6
|
require 'benchmark'
|
7
7
|
|
8
|
-
|
8
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/spec')
|
9
|
+
|
10
|
+
task :default do
|
11
|
+
config = File.open(File.expand_path(File.dirname(__FILE__) + '/spec/config.yml')).read
|
12
|
+
if config.match /<username>/
|
13
|
+
print "Would you like to create and configure the test database? y/n "
|
14
|
+
continue = STDIN.getc
|
15
|
+
exit 0 unless continue == "Y" || continue == "y"
|
16
|
+
sh "createdb texticle"
|
17
|
+
File.open(File.expand_path(File.dirname(__FILE__) + '/spec/config.yml'), "w") do |writable_config|
|
18
|
+
writable_config << config.sub(/<username>/, `whoami`.chomp)
|
19
|
+
end
|
20
|
+
Rake::Task["db:migrate"].invoke
|
21
|
+
end
|
22
|
+
Rake::Task["test"].invoke
|
23
|
+
end
|
24
|
+
|
25
|
+
task :test do
|
26
|
+
require 'texticle_spec'
|
27
|
+
require 'texticle/searchable_spec'
|
28
|
+
end
|
9
29
|
|
10
30
|
namespace :db do
|
11
31
|
desc 'Run migrations for test database'
|
12
32
|
task :migrate do
|
33
|
+
require 'spec_helper'
|
13
34
|
ActiveRecord::Migration.instance_eval do
|
14
35
|
create_table :games do |table|
|
15
36
|
table.string :system
|
16
37
|
table.string :title
|
38
|
+
table.text :description
|
17
39
|
end
|
18
40
|
create_table :web_comics do |table|
|
19
41
|
table.string :name
|
20
42
|
table.string :author
|
43
|
+
table.text :review
|
44
|
+
table.integer :id
|
45
|
+
end
|
46
|
+
create_table :characters do |table|
|
47
|
+
table.string :name
|
48
|
+
table.string :description
|
49
|
+
table.integer :web_comic_id
|
21
50
|
end
|
22
51
|
end
|
23
52
|
end
|
24
53
|
desc 'Drop tables from test database'
|
25
54
|
task :drop do
|
55
|
+
require 'spec_helper'
|
26
56
|
ActiveRecord::Migration.instance_eval do
|
27
57
|
drop_table :games
|
28
58
|
drop_table :web_comics
|
59
|
+
drop_table :characters
|
29
60
|
end
|
30
61
|
end
|
31
62
|
end
|
data/lib/texticle.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
|
3
3
|
module Texticle
|
4
|
-
|
5
4
|
def search(query = "", exclusive = true)
|
6
|
-
|
5
|
+
@similarities = []
|
6
|
+
@conditions = []
|
7
7
|
|
8
8
|
unless query.is_a?(Hash)
|
9
9
|
exclusive = false
|
@@ -12,20 +12,12 @@ module Texticle
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
conditions = []
|
17
|
-
|
18
|
-
query.each do |column, search_term|
|
19
|
-
column = connection.quote_column_name(column)
|
20
|
-
search_term = connection.quote normalize(Helper.normalize(search_term))
|
21
|
-
similarities << "ts_rank(to_tsvector(#{language}, #{quoted_table_name}.#{column}), to_tsquery(#{language}, #{search_term}))"
|
22
|
-
conditions << "to_tsvector(#{language}, #{column}) @@ to_tsquery(#{language}, #{search_term})"
|
23
|
-
end
|
15
|
+
parse_query_hash(query)
|
24
16
|
|
25
17
|
rank = connection.quote_column_name('rank' + rand.to_s)
|
26
18
|
|
27
|
-
select("#{quoted_table_name + '.*,' if scoped.select_values.empty?} #{similarities.join(" + ")} AS #{rank}").
|
28
|
-
where(conditions.join(exclusive ? " AND " : " OR ")).
|
19
|
+
select("#{quoted_table_name + '.*,' if scoped.select_values.empty?} #{@similarities.join(" + ")} AS #{rank}").
|
20
|
+
where(@conditions.join(exclusive ? " AND " : " OR ")).
|
29
21
|
order("#{rank} DESC")
|
30
22
|
end
|
31
23
|
|
@@ -45,23 +37,41 @@ module Texticle
|
|
45
37
|
else
|
46
38
|
super
|
47
39
|
end
|
40
|
+
rescue ActiveRecord::StatementInvalid
|
41
|
+
super
|
48
42
|
end
|
49
43
|
|
50
44
|
def respond_to?(method, include_private = false)
|
51
45
|
return super if self == ActiveRecord::Base
|
52
46
|
Helper.dynamic_search_method?(method, self.columns) or super
|
53
|
-
rescue
|
47
|
+
rescue StandardError
|
54
48
|
super
|
55
49
|
end
|
56
50
|
|
57
51
|
private
|
58
52
|
|
53
|
+
def parse_query_hash(query, table_name = quoted_table_name)
|
54
|
+
language = connection.quote(searchable_language)
|
55
|
+
table_name = connection.quote_table_name(table_name)
|
56
|
+
|
57
|
+
query.each do |column_or_table, search_term|
|
58
|
+
if search_term.is_a?(Hash)
|
59
|
+
parse_query_hash(search_term, column_or_table)
|
60
|
+
else
|
61
|
+
column = connection.quote_column_name(column_or_table)
|
62
|
+
search_term = connection.quote normalize(Helper.normalize(search_term))
|
63
|
+
@similarities << "ts_rank(to_tsvector(#{language}, #{table_name}.#{column}::text), to_tsquery(#{language}, #{search_term}::text))"
|
64
|
+
@conditions << "to_tsvector(#{language}, #{table_name}.#{column}::text) @@ to_tsquery(#{language}, #{search_term}::text)"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
59
69
|
def normalize(query)
|
60
70
|
query
|
61
71
|
end
|
62
72
|
|
63
73
|
def searchable_columns
|
64
|
-
columns.select {|column| column.type
|
74
|
+
columns.select {|column| [:string, :text].include? column.type }.map(&:name)
|
65
75
|
end
|
66
76
|
|
67
77
|
def searchable_language
|
@@ -91,7 +101,7 @@ module Texticle
|
|
91
101
|
end
|
92
102
|
|
93
103
|
def exclusive_dynamic_search_method?(method, class_columns)
|
94
|
-
string_columns = class_columns.
|
104
|
+
string_columns = class_columns.map(&:name)
|
95
105
|
columns = exclusive_dynamic_search_columns(method)
|
96
106
|
unless columns.empty?
|
97
107
|
columns.all? {|column| string_columns.include?(column) }
|
@@ -101,7 +111,7 @@ module Texticle
|
|
101
111
|
end
|
102
112
|
|
103
113
|
def inclusive_dynamic_search_method?(method, class_columns)
|
104
|
-
string_columns = class_columns.
|
114
|
+
string_columns = class_columns.map(&:name)
|
105
115
|
columns = inclusive_dynamic_search_columns(method)
|
106
116
|
unless columns.empty?
|
107
117
|
columns.all? {|column| string_columns.include?(column) }
|
@@ -116,5 +126,4 @@ module Texticle
|
|
116
126
|
end
|
117
127
|
end
|
118
128
|
end
|
119
|
-
|
120
129
|
end
|
data/lib/texticle/searchable.rb
CHANGED
@@ -1,16 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'fixtures/webcomic'
|
2
3
|
require 'texticle/searchable'
|
3
4
|
|
4
|
-
class WebComic < ActiveRecord::Base
|
5
|
-
# string :name
|
6
|
-
# string :author
|
7
|
-
end
|
8
|
-
|
9
5
|
class SearchableTest < Test::Unit::TestCase
|
10
|
-
|
11
6
|
context "when extending an ActiveRecord::Base subclass" do
|
12
7
|
setup do
|
13
|
-
@qcont = WebComic.create :name => "Questionable Content", :author => "
|
8
|
+
@qcont = WebComic.create :name => "Questionable Content", :author => "Jeph Jaques"
|
14
9
|
@jhony = WebComic.create :name => "Johnny Wander", :author => "Ananth & Yuko"
|
15
10
|
@ddeeg = WebComic.create :name => "Dominic Deegan", :author => "Mookie"
|
16
11
|
@penny = WebComic.create :name => "Penny Arcade", :author => "Tycho & Gabe"
|
@@ -18,11 +13,12 @@ class SearchableTest < Test::Unit::TestCase
|
|
18
13
|
|
19
14
|
teardown do
|
20
15
|
WebComic.delete_all
|
16
|
+
#Object.send(:remove_const, :WebComic) if defined?(WebComic)
|
21
17
|
end
|
22
18
|
|
23
|
-
context "with no
|
19
|
+
context "with no parameters" do
|
24
20
|
setup do
|
25
|
-
WebComic.extend
|
21
|
+
WebComic.extend Searchable
|
26
22
|
end
|
27
23
|
|
28
24
|
should "search across all columns" do
|
@@ -33,18 +29,27 @@ class SearchableTest < Test::Unit::TestCase
|
|
33
29
|
|
34
30
|
context "with one column as parameter" do
|
35
31
|
setup do
|
36
|
-
WebComic.extend
|
32
|
+
WebComic.extend Searchable(:name)
|
37
33
|
end
|
38
34
|
|
39
35
|
should "only search across the given column" do
|
40
36
|
assert_equal [@penny], WebComic.search("Penny")
|
41
37
|
assert_empty WebComic.search("Tycho")
|
42
38
|
end
|
39
|
+
|
40
|
+
should "define :searchable_columns as private" do
|
41
|
+
assert_raise(NoMethodError) { WebComic.searchable_columns }
|
42
|
+
begin
|
43
|
+
WebComic.searchable_columns
|
44
|
+
rescue NoMethodError => error
|
45
|
+
assert_match error.message, /private method/
|
46
|
+
end
|
47
|
+
end
|
43
48
|
end
|
44
49
|
|
45
50
|
context "with two columns as parameters" do
|
46
51
|
setup do
|
47
|
-
WebComic.extend
|
52
|
+
WebComic.extend Searchable(:name, :author)
|
48
53
|
end
|
49
54
|
|
50
55
|
should "only search across the given column" do
|
@@ -53,5 +58,4 @@ class SearchableTest < Test::Unit::TestCase
|
|
53
58
|
end
|
54
59
|
end
|
55
60
|
end
|
56
|
-
|
57
61
|
end
|
data/spec/texticle_spec.rb
CHANGED
@@ -1,25 +1,14 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
require 'spec_helper'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# string :title
|
7
|
-
|
8
|
-
def to_s
|
9
|
-
"#{system}: #{title}"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class NotThere < ActiveRecord::Base
|
14
|
-
|
15
|
-
end
|
3
|
+
require 'fixtures/webcomic'
|
4
|
+
require 'fixtures/character'
|
5
|
+
require 'fixtures/game'
|
16
6
|
|
17
7
|
class TexticleTest < Test::Unit::TestCase
|
18
|
-
|
19
8
|
context "after extending ActiveRecord::Base" do
|
20
|
-
|
21
|
-
|
22
|
-
end
|
9
|
+
# before(:all)
|
10
|
+
ActiveRecord::Base.extend(Texticle)
|
11
|
+
class NotThere < ActiveRecord::Base; end
|
23
12
|
|
24
13
|
should "not break #respond_to?" do
|
25
14
|
assert_nothing_raised do
|
@@ -35,31 +24,85 @@ class TexticleTest < Test::Unit::TestCase
|
|
35
24
|
end
|
36
25
|
|
37
26
|
should "not break #method_missing" do
|
27
|
+
assert_raise(NoMethodError) { ActiveRecord::Base.random }
|
38
28
|
begin
|
39
29
|
ActiveRecord::Base.random
|
40
30
|
rescue NoMethodError => error
|
41
31
|
assert_match error.message, /undefined method `random'/
|
42
32
|
end
|
43
33
|
end
|
34
|
+
|
35
|
+
should "not break #method_missing for table-less classes" do
|
36
|
+
assert !NotThere.table_exists?
|
37
|
+
assert_raise(NoMethodError) { NotThere.random }
|
38
|
+
begin
|
39
|
+
NotThere.random
|
40
|
+
rescue NoMethodError => error
|
41
|
+
assert_match error.message, /undefined method `random'/
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when finding models based on searching a related model" do
|
46
|
+
setup do
|
47
|
+
@qc = WebComic.create :name => "Questionable Content", :author => "Jeph Jaques"
|
48
|
+
@jw = WebComic.create :name => "Johnny Wander", :author => "Ananth & Yuko"
|
49
|
+
@pa = WebComic.create :name => "Penny Arcade", :author => "Tycho & Gabe"
|
50
|
+
|
51
|
+
@gabe = @pa.characters.create :name => 'Gabe', :description => 'the simple one'
|
52
|
+
@tycho = @pa.characters.create :name => 'Tycho', :description => 'the wordy one'
|
53
|
+
@div = @pa.characters.create :name => 'Div', :description => 'a crude divx player with anger management issues'
|
54
|
+
|
55
|
+
@martin = @qc.characters.create :name => 'Martin', :description => 'the insecure protagonist'
|
56
|
+
@faye = @qc.characters.create :name => 'Faye', :description => 'a sarcastic barrista with anger management issues'
|
57
|
+
@pintsize = @qc.characters.create :name => 'Pintsize', :description => 'a crude AnthroPC'
|
58
|
+
|
59
|
+
@ananth = @jw.characters.create :name => 'Ananth', :description => 'Stubble! What is under that hat?!?'
|
60
|
+
@yuko = @jw.characters.create :name => 'Yuko', :description => 'So... small. Carl Sagan haircut.'
|
61
|
+
@john = @jw.characters.create :name => 'John', :description => 'Tall. Anger issues?'
|
62
|
+
@cricket = @jw.characters.create :name => 'Cricket', :description => 'Chirrup!'
|
63
|
+
end
|
64
|
+
|
65
|
+
teardown do
|
66
|
+
WebComic.delete_all
|
67
|
+
Character.delete_all
|
68
|
+
end
|
69
|
+
|
70
|
+
should "look in the related model with nested searching syntax" do
|
71
|
+
assert_equal [@jw], WebComic.joins(:characters).search(:characters => {:description => 'tall'})
|
72
|
+
assert_equal [@pa, @jw, @qc].sort, WebComic.joins(:characters).search(:characters => {:description => 'anger'}).sort
|
73
|
+
assert_equal [@pa, @qc].sort, WebComic.joins(:characters).search(:characters => {:description => 'crude'}).sort
|
74
|
+
end
|
75
|
+
end
|
44
76
|
end
|
45
77
|
|
46
78
|
context "after extending an ActiveRecord::Base subclass" do
|
79
|
+
# before(:all)
|
80
|
+
class ::GameFail < Game; end
|
81
|
+
|
47
82
|
setup do
|
48
|
-
Game.
|
49
|
-
@
|
50
|
-
@
|
51
|
-
@
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@
|
55
|
-
@
|
56
|
-
@takun = Game.create :system => "Saturn", :title => "Magical Tarurūto-kun"
|
83
|
+
@zelda = Game.create :system => "NES", :title => "Legend of Zelda", :description => "A Link to the Past."
|
84
|
+
@mario = Game.create :system => "NES", :title => "Super Mario Bros.", :description => "The original platformer."
|
85
|
+
@sonic = Game.create :system => "Genesis", :title => "Sonic the Hedgehog", :description => "Spiky."
|
86
|
+
@dkong = Game.create :system => "SNES", :title => "Diddy's Kong Quest", :description => "Donkey Kong Country 2"
|
87
|
+
@megam = Game.create :system => nil, :title => "Mega Man", :description => "Beware Dr. Brain"
|
88
|
+
@sfnes = Game.create :system => "SNES", :title => "Street Fighter 2", :description => "Yoga Flame!"
|
89
|
+
@sfgen = Game.create :system => "Genesis", :title => "Street Fighter 2", :description => "Yoga Flame!"
|
90
|
+
@takun = Game.create :system => "Saturn", :title => "Magical Tarurūto-kun", :description => "カッコイイ!"
|
57
91
|
end
|
58
92
|
|
59
93
|
teardown do
|
60
94
|
Game.delete_all
|
61
95
|
end
|
62
96
|
|
97
|
+
should "not break respond_to? when connection is unavailable" do
|
98
|
+
GameFail.establish_connection({:adapter => :postgresql, :database =>'unavailable', :username=>'bad', :pool=>5, :timeout=>5000}) rescue nil
|
99
|
+
|
100
|
+
assert_nothing_raised do
|
101
|
+
GameFail.respond_to?(:search)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
63
106
|
should "define a #search method" do
|
64
107
|
assert Game.respond_to?(:search)
|
65
108
|
end
|
@@ -108,6 +151,10 @@ class TexticleTest < Test::Unit::TestCase
|
|
108
151
|
should "scope consecutively" do
|
109
152
|
assert_equal [@sfgen], Game.search(:system => "Genesis").search(:title => "Street Fighter")
|
110
153
|
end
|
154
|
+
|
155
|
+
should "cast non-:string columns as text" do
|
156
|
+
assert_equal [@mario], Game.search(:id => @mario.id)
|
157
|
+
end
|
111
158
|
end
|
112
159
|
|
113
160
|
context "when using dynamic search methods" do
|
@@ -116,10 +163,15 @@ class TexticleTest < Test::Unit::TestCase
|
|
116
163
|
assert_equal [@takun], Game.search_by_system("Saturn")
|
117
164
|
end
|
118
165
|
|
119
|
-
should "generate methods for
|
166
|
+
should "generate methods for each :text column" do
|
167
|
+
assert_equal [@mario], Game.search_by_description("platform")
|
168
|
+
end
|
169
|
+
|
170
|
+
should "generate methods for any combination of :string and :text columns" do
|
120
171
|
assert_equal [@mario], Game.search_by_title_and_system("Mario", "NES")
|
121
172
|
assert_equal [@sonic], Game.search_by_system_and_title("Genesis", "Sonic")
|
122
173
|
assert_equal [@mario], Game.search_by_title_and_title("Mario", "Mario")
|
174
|
+
assert_equal [@megam], Game.search_by_title_and_description("Man", "Brain")
|
123
175
|
end
|
124
176
|
|
125
177
|
should "generate methods for inclusive searches" do
|
@@ -130,8 +182,8 @@ class TexticleTest < Test::Unit::TestCase
|
|
130
182
|
assert_equal [@sfgen], Game.search_by_system("Genesis").search_by_title("Street Fighter")
|
131
183
|
end
|
132
184
|
|
133
|
-
should "
|
134
|
-
|
185
|
+
should "generate methods for non-:string columns" do
|
186
|
+
assert_equal [@mario], Game.search_by_id(@mario.id)
|
135
187
|
end
|
136
188
|
|
137
189
|
should "work with #respond_to?" do
|
@@ -140,8 +192,8 @@ class TexticleTest < Test::Unit::TestCase
|
|
140
192
|
assert Game.respond_to?(:search_by_system_and_title)
|
141
193
|
assert Game.respond_to?(:search_by_system_or_title)
|
142
194
|
assert Game.respond_to?(:search_by_title_and_title_and_title)
|
195
|
+
assert Game.respond_to?(:search_by_id)
|
143
196
|
|
144
|
-
assert !Game.respond_to?(:search_by_id)
|
145
197
|
assert !Game.respond_to?(:search_by_title_and_title_or_title)
|
146
198
|
end
|
147
199
|
|
@@ -160,24 +212,20 @@ class TexticleTest < Test::Unit::TestCase
|
|
160
212
|
end
|
161
213
|
|
162
214
|
context "when setting a custom search language" do
|
215
|
+
def Game.searchable_language
|
216
|
+
'spanish'
|
217
|
+
end
|
218
|
+
|
163
219
|
setup do
|
164
|
-
def Game.searchable_language
|
165
|
-
'spanish'
|
166
|
-
end
|
167
220
|
Game.create :system => "PS3", :title => "Harry Potter & the Deathly Hallows"
|
168
221
|
end
|
169
222
|
|
170
223
|
teardown do
|
171
|
-
def Game.searchable_language
|
172
|
-
'english'
|
173
|
-
end
|
174
224
|
Game.delete_all
|
175
225
|
end
|
176
226
|
|
177
227
|
should "still find results" do
|
178
228
|
assert_not_empty Game.search_by_title("harry")
|
179
|
-
p
|
180
229
|
end
|
181
230
|
end
|
182
|
-
|
183
231
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: texticle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,42 +10,63 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-08-30 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: pg
|
18
|
-
requirement: &
|
17
|
+
requirement: &70337748621180 !ruby/object:Gem::Requirement
|
19
18
|
none: false
|
20
19
|
requirements:
|
21
|
-
- -
|
20
|
+
- - ~>
|
22
21
|
- !ruby/object:Gem::Version
|
23
22
|
version: 0.11.0
|
24
23
|
type: :development
|
25
24
|
prerelease: false
|
26
|
-
version_requirements: *
|
25
|
+
version_requirements: *70337748621180
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
27
|
name: shoulda
|
29
|
-
requirement: &
|
28
|
+
requirement: &70337748620400 !ruby/object:Gem::Requirement
|
30
29
|
none: false
|
31
30
|
requirements:
|
32
|
-
- -
|
31
|
+
- - ~>
|
33
32
|
- !ruby/object:Gem::Version
|
34
33
|
version: 2.11.3
|
35
34
|
type: :development
|
36
35
|
prerelease: false
|
37
|
-
version_requirements: *
|
36
|
+
version_requirements: *70337748620400
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
39
|
+
requirement: &70337748619540 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 0.8.0
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70337748619540
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: ruby-debug19
|
50
|
+
requirement: &70337748618760 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 0.11.6
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *70337748618760
|
38
59
|
- !ruby/object:Gem::Dependency
|
39
60
|
name: activerecord
|
40
|
-
requirement: &
|
61
|
+
requirement: &70337748617780 !ruby/object:Gem::Requirement
|
41
62
|
none: false
|
42
63
|
requirements:
|
43
|
-
- -
|
64
|
+
- - ~>
|
44
65
|
- !ruby/object:Gem::Version
|
45
|
-
version: 3.0
|
66
|
+
version: '3.0'
|
46
67
|
type: :runtime
|
47
68
|
prerelease: false
|
48
|
-
version_requirements: *
|
69
|
+
version_requirements: *70337748617780
|
49
70
|
description: ! "Texticle exposes full text search capabilities from PostgreSQL, extending\n
|
50
71
|
\ ActiveRecord with scopes making search easy and fun!"
|
51
72
|
email:
|
@@ -68,7 +89,6 @@ files:
|
|
68
89
|
- spec/texticle_spec.rb
|
69
90
|
- spec/texticle/searchable_spec.rb
|
70
91
|
- spec/config.yml
|
71
|
-
has_rdoc: true
|
72
92
|
homepage: http://tenderlove.github.com/texticle
|
73
93
|
licenses: []
|
74
94
|
post_install_message:
|
@@ -91,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
111
|
version: '0'
|
92
112
|
requirements: []
|
93
113
|
rubyforge_project: texticle
|
94
|
-
rubygems_version: 1.
|
114
|
+
rubygems_version: 1.8.10
|
95
115
|
signing_key:
|
96
116
|
specification_version: 3
|
97
117
|
summary: Texticle exposes full text search capabilities from PostgreSQL
|