texticle 2.0.pre3 → 2.0.pre4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,23 @@
1
+ == 2.0.pre4
2
+
3
+ * 1 new feature
4
+
5
+ * Searchable is now available to specify which columns you want searched:
6
+
7
+ require 'texticle/searchable'
8
+ class Game
9
+ include Searchable(:title)
10
+ end
11
+
12
+ This also allows Texticle use in Rails without having #search available to all models:
13
+
14
+ gem 'texticle', '~> 2.0.pre4', :require => 'texticle/searchable'
15
+
16
+ * 1 bugfix
17
+
18
+ * ActiveRecord::Base.extend(Texticle) doesn't break #method_missing and #respond_to? anymore
19
+
20
+
1
21
  == 2.0.pre3
2
22
 
3
23
  * 1 new feature
data/Manifest.txt CHANGED
@@ -4,10 +4,9 @@ Manifest.txt
4
4
  README.rdoc
5
5
  Rakefile
6
6
  lib/texticle.rb
7
- lib/texticle/full_text_index.rb
8
- lib/texticle/railtie.rb
9
- lib/texticle/tasks.rb
10
- rails/init.rb
11
- test/helper.rb
12
- test/test_full_text_index.rb
13
- test/test_texticle.rb
7
+ lib/texticle/rails.rb
8
+ lib/texticle/searchable.rb
9
+ spec/config.yml
10
+ spec/spec_helper.rb
11
+ spec/texticle_spec.rb
12
+ spec/texticle/searchable_spec.rb
data/README.rdoc CHANGED
@@ -1,5 +1,7 @@
1
1
  = texticle
2
2
 
3
+ Further documentation available at:
4
+
3
5
  * http://tenderlove.github.com/texticle
4
6
 
5
7
  == DESCRIPTION:
@@ -33,6 +35,7 @@ Your models now have access to the search method:
33
35
  Game.search('Sonic') # will search through the model's :string columns
34
36
  Game.search(:title => 'Mario')
35
37
  Game.search_by_title('Street Fighter').search_by_system('PS3')
38
+ Game.search_by_title_and_system('Final Fantasy', 'PS2')
36
39
 
37
40
  == REQUIREMENTS:
38
41
 
data/Rakefile CHANGED
@@ -15,6 +15,17 @@ namespace :db do
15
15
  table.string :system
16
16
  table.string :title
17
17
  end
18
+ create_table :web_comics do |table|
19
+ table.string :name
20
+ table.string :author
21
+ end
22
+ end
23
+ end
24
+ desc 'Drop tables from test database'
25
+ task :drop do
26
+ ActiveRecord::Migration.instance_eval do
27
+ drop_table :games
28
+ drop_table :web_comics
18
29
  end
19
30
  end
20
31
  end
@@ -0,0 +1,16 @@
1
+ require 'texticle'
2
+
3
+ def Searchable(*searchable_columns)
4
+ Module.new do
5
+
6
+ include Texticle
7
+
8
+ private
9
+
10
+ define_method(:searchable_columns) do
11
+ searchable_columns.map(&:to_s)
12
+ end
13
+ end
14
+ end
15
+
16
+ Searchable = Texticle
data/lib/texticle.rb CHANGED
@@ -6,11 +6,10 @@ module Texticle
6
6
  language = connection.quote('english')
7
7
 
8
8
  exclusive = true
9
- string_columns = columns.select {|column| column.type == :string }.map(&:name)
10
9
 
11
10
  unless query.is_a?(Hash)
12
11
  exclusive = false
13
- query = string_columns.inject({}) do |terms, column|
12
+ query = searchable_columns.inject({}) do |terms, column|
14
13
  terms.merge column => query.to_s
15
14
  end
16
15
  end
@@ -18,11 +17,6 @@ module Texticle
18
17
  similarities = []
19
18
  conditions = []
20
19
 
21
- select_values = scoped.select_values.map(&:to_s) & string_columns
22
- query.select! do |column, search_term|
23
- select_values.include? column
24
- end unless select_values.empty?
25
-
26
20
  query.each do |column, search_term|
27
21
  column = connection.quote_column_name(column)
28
22
  search_term = connection.quote normalize(Helper.normalize(search_term))
@@ -32,12 +26,13 @@ module Texticle
32
26
 
33
27
  rank = connection.quote_column_name('rank' + rand.to_s)
34
28
 
35
- select("#{quoted_table_name + '.*,' if select_values.empty?} #{similarities.join(" + ")} AS #{rank}").
29
+ select("#{quoted_table_name + '.*,' if scoped.select_values.empty?} #{similarities.join(" + ")} AS #{rank}").
36
30
  where(conditions.join(exclusive ? " AND " : " OR ")).
37
31
  order("#{rank} DESC")
38
32
  end
39
33
 
40
34
  def method_missing(method, *search_terms)
35
+ return super if self == ActiveRecord::Base
41
36
  if Helper.dynamic_search_method?(method, self.columns)
42
37
  columns = Helper.dynamic_search_columns(method)
43
38
  metaclass = class << self; self; end
@@ -54,6 +49,7 @@ module Texticle
54
49
  end
55
50
 
56
51
  def respond_to?(method, include_private = false)
52
+ return super if self == ActiveRecord::Base
57
53
  Helper.dynamic_search_method?(method, self.columns) ? true : super
58
54
  end
59
55
 
@@ -63,6 +59,10 @@ module Texticle
63
59
  query
64
60
  end
65
61
 
62
+ def searchable_columns
63
+ columns.select {|column| column.type == :string }.map(&:name)
64
+ end
65
+
66
66
  module Helper
67
67
  class << self
68
68
  def normalize(query)
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'texticle/searchable'
3
+
4
+ class WebComic < ActiveRecord::Base
5
+ # string :name
6
+ # string :author
7
+ end
8
+
9
+ class SearchableTest < Test::Unit::TestCase
10
+
11
+ context "when extending an ActiveRecord::Base subclass" do
12
+ setup do
13
+ @qcont = WebComic.create :name => "Questionable Content", :author => "Jeff Jaques"
14
+ @jhony = WebComic.create :name => "Johnny Wander", :author => "Ananth & Yuko"
15
+ @ddeeg = WebComic.create :name => "Dominic Deegan", :author => "Mookie"
16
+ @penny = WebComic.create :name => "Penny Arcade", :author => "Tycho & Gabe"
17
+ end
18
+
19
+ teardown do
20
+ WebComic.delete_all
21
+ end
22
+
23
+ context "with no paramters" do
24
+ setup do
25
+ WebComic.extend(Searchable)
26
+ end
27
+
28
+ should "search across all columns" do
29
+ assert_equal [@penny], WebComic.search("Penny")
30
+ assert_equal [@ddeeg], WebComic.search("Dominic")
31
+ end
32
+ end
33
+
34
+ context "with one column as parameter" do
35
+ setup do
36
+ WebComic.extend(Searchable(:name))
37
+ end
38
+
39
+ should "only search across the given column" do
40
+ assert_equal [@penny], WebComic.search("Penny")
41
+ assert_empty WebComic.search("Tycho")
42
+ end
43
+ end
44
+
45
+ context "with two columns as parameters" do
46
+ setup do
47
+ WebComic.extend(Searchable(:name, :author))
48
+ end
49
+
50
+ should "only search across the given column" do
51
+ assert_equal [@penny], WebComic.search("Penny")
52
+ assert_equal [@penny], WebComic.search("Tycho")
53
+ end
54
+ end
55
+ end
56
+
57
+ end
@@ -12,6 +12,26 @@ end
12
12
 
13
13
  class TexticleTest < Test::Unit::TestCase
14
14
 
15
+ context "after extending ActiveRecord::Base" do
16
+ setup do
17
+ ActiveRecord::Base.extend(Texticle)
18
+ end
19
+
20
+ should "not break #respond_to?" do
21
+ assert_nothing_raised do
22
+ ActiveRecord::Base.respond_to? :abstract_class?
23
+ end
24
+ end
25
+
26
+ should "not break #method_missing" do
27
+ begin
28
+ ActiveRecord::Base.random
29
+ rescue NoMethodError => error
30
+ assert_match error.message, /undefined method `random'/
31
+ end
32
+ end
33
+ end
34
+
15
35
  context "after extending an ActiveRecord::Base subclass" do
16
36
  setup do
17
37
  Game.extend(Texticle)
@@ -35,70 +55,64 @@ class TexticleTest < Test::Unit::TestCase
35
55
 
36
56
  context "when searching with a String argument" do
37
57
  should "search across all :string columns if no indexes have been specified" do
38
- assert_equal @mario, Game.search("Mario").first
39
- assert_equal 1, Game.search("Mario").count
40
-
41
- assert (Game.search("NES") && [@mario, @zelda]) == [@mario, @zelda]
42
- assert_equal 2, Game.search("NES").count
58
+ assert_equal [@mario], Game.search("Mario")
59
+ assert_equal Set.new([@mario, @zelda]), Game.search("NES").to_set
43
60
  end
44
61
 
45
62
  should "work if the query contains an apostrophe" do
46
- assert_equal @dkong, Game.search("Diddy's").first
47
- assert_equal 1, Game.search("Diddy's").count
63
+ assert_equal [@dkong], Game.search("Diddy's")
48
64
  end
49
65
 
50
66
  should "work if the query contains whitespace" do
51
- assert_equal @megam, Game.search("Mega Man").first
67
+ assert_equal [@megam], Game.search("Mega Man")
52
68
  end
53
69
 
54
70
  should "work if the query contains an accent" do
55
- assert_equal @takun, Game.search("Tarurūto-kun").first
71
+ assert_equal [@takun], Game.search("Tarurūto-kun")
56
72
  end
57
73
 
58
74
  should "search across records with NULL values" do
59
- assert_equal @megam, Game.search("Mega").first
75
+ assert_equal [@megam], Game.search("Mega")
60
76
  end
61
77
 
62
78
  should "scope consecutively" do
63
- assert_equal @sfgen, Game.search("Genesis").search("Street Fighter").first
79
+ assert_equal [@sfgen], Game.search("Genesis").search("Street Fighter")
64
80
  end
65
81
  end
66
82
 
67
83
  context "when searching with a Hash argument" do
68
84
  should "search across the given columns" do
69
- assert Game.search(:title => "NES").empty?
70
- assert Game.search(:system => "Mario").empty?
71
- puts Game.search(:system => "NES", :title => "Sonic").to_a
72
- assert Game.search(:system => "NES", :title => "Sonic").empty?
85
+ assert_empty Game.search(:title => "NES")
86
+ assert_empty Game.search(:system => "Mario")
87
+ assert_empty Game.search(:system => "NES", :title => "Sonic")
73
88
 
74
- assert_equal @mario, Game.search(:title => "Mario").first
75
- assert_equal 1, Game.search(:title => "Mario").count
89
+ assert_equal [@mario], Game.search(:title => "Mario")
76
90
 
77
- assert_equal 2, Game.search(:system => "NES").count
91
+ assert_equal 2, Game.search(:system => "NES").count
78
92
 
79
- assert_equal @zelda, Game.search(:system => "NES", :title => "Zelda").first
80
- assert_equal @megam, Game.search(:title => "Mega").first
93
+ assert_equal [@zelda], Game.search(:system => "NES", :title => "Zelda")
94
+ assert_equal [@megam], Game.search(:title => "Mega")
81
95
  end
82
96
 
83
97
  should "scope consecutively" do
84
- assert_equal @sfgen, Game.search(:system => "Genesis").search(:title => "Street Fighter").first
98
+ assert_equal [@sfgen], Game.search(:system => "Genesis").search(:title => "Street Fighter")
85
99
  end
86
100
  end
87
101
 
88
102
  context "when using dynamic search methods" do
89
103
  should "generate methods for each :string column" do
90
- assert_equal @mario, Game.search_by_title("Mario").first
91
- assert_equal @takun, Game.search_by_system("Saturn").first
104
+ assert_equal [@mario], Game.search_by_title("Mario")
105
+ assert_equal [@takun], Game.search_by_system("Saturn")
92
106
  end
93
107
 
94
108
  should "generate methods for any combination of :string columns" do
95
- assert_equal @mario, Game.search_by_title_and_system("Mario", "NES").first
96
- assert_equal @sonic, Game.search_by_system_and_title("Genesis", "Sonic").first
97
- assert_equal @mario, Game.search_by_title_and_title("Mario", "Mario").first
109
+ assert_equal [@mario], Game.search_by_title_and_system("Mario", "NES")
110
+ assert_equal [@sonic], Game.search_by_system_and_title("Genesis", "Sonic")
111
+ assert_equal [@mario], Game.search_by_title_and_title("Mario", "Mario")
98
112
  end
99
113
 
100
114
  should "scope consecutively" do
101
- assert_equal @sfgen, Game.search_by_system("Genesis").search_by_title("Street Fighter").first
115
+ assert_equal [@sfgen], Game.search_by_system("Genesis").search_by_title("Street Fighter")
102
116
  end
103
117
 
104
118
  should "not generate methods for non-:string columns" do
@@ -120,11 +134,6 @@ class TexticleTest < Test::Unit::TestCase
120
134
  end
121
135
 
122
136
  context "when searching after selecting columns to return" do
123
- should "limit the search to the selected columns" do
124
- assert_empty Game.select(:system).search("Mario")
125
- assert_equal @mario.title, Game.select(:title).search("Mario").first.title
126
- end
127
-
128
137
  should "not fetch extra columns" do
129
138
  assert_raise(ActiveModel::MissingAttributeError) do
130
139
  Game.select(:title).search("Mario").first.system
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: texticle
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 4
5
- version: 2.0.pre3
5
+ version: 2.0.pre4
6
6
  platform: ruby
7
7
  authors:
8
8
  - ecin
@@ -65,9 +65,11 @@ files:
65
65
  - README.rdoc
66
66
  - Rakefile
67
67
  - lib/texticle.rb
68
+ - lib/texticle/searchable.rb
68
69
  - lib/texticle/rails.rb
69
70
  - spec/spec_helper.rb
70
71
  - spec/texticle_spec.rb
72
+ - spec/texticle/searchable_spec.rb
71
73
  - spec/config.yml
72
74
  homepage: http://tenderlove.github.com/texticle
73
75
  licenses: []