texticle 2.0.pre3 → 2.0.pre4

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 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: []