pose 0.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,7 @@ Pose ("Polymorphic Search") allows fulltext search for ActiveRecord objects.
5
5
  * Searches over several ActiveRecord classes at once.
6
6
  * The searchable fulltext content per document can be freely customized.
7
7
  * Uses the Rails database, no sparate search engines are necessary.
8
- * The algorithm is designed to work with any data store that allows for range queries: SQL and NoSQL.
8
+ * The algorithm is designed to work with any data store that allows for range queries: SQL and NoSQL.
9
9
  * The search runs very fast, doing simple queries over fully indexed columns.
10
10
  * The search index provides data for autocomplete search fields.
11
11
 
@@ -14,17 +14,23 @@ Pose ("Polymorphic Search") allows fulltext search for ActiveRecord objects.
14
14
 
15
15
  1. Add the gem to your Gemfile.
16
16
 
17
- gem 'pose'
17
+ ```ruby
18
+ gem 'pose'
19
+ ```
18
20
 
19
21
  2. Update your gem bundle.
20
22
 
21
- $ bundle install
23
+ ```bash
24
+ $ bundle install
25
+ ```
22
26
 
23
27
  3. Create the database tables for pose.
24
28
 
25
- $ rails generate pose
26
- $ rake db:migrate
27
-
29
+ ```bash
30
+ $ rails generate pose
31
+ $ rake db:migrate
32
+ ```
33
+
28
34
  Pose creates two tables in your database:
29
35
 
30
36
  * _pose_words_: index of all the words that occur in the searchable content.
@@ -33,25 +39,27 @@ Pose ("Polymorphic Search") allows fulltext search for ActiveRecord objects.
33
39
 
34
40
  # Make your ActiveRecord models searchable
35
41
 
36
- class MyClass < ActiveRecord::Base
37
-
38
- # This line tells Pose that your class should be searchable.
39
- # Once Pose knows that, it will update the search index every time an instance is saved or deleted.
40
- #
41
- # The given block must return the searchble content as a string.
42
- # Note that you can return whatever content you want here,
43
- # not only data from this object but also data from related objects, class names, etc.
44
- posify do
45
-
46
- # Only active instances should show up in search results.
47
- return unless status == :active
48
-
49
- # Return the fulltext content.
50
- [ self.foo,
51
- self.parent.bar,
52
- self.children.map &:name ].join ' '
53
- end
54
- end
42
+ ```ruby
43
+ class MyClass < ActiveRecord::Base
44
+
45
+ # This line tells Pose that your class should be searchable.
46
+ # Once Pose knows that, it will update the search index every time an instance is saved or deleted.
47
+ #
48
+ # The given block must return the searchble content as a string.
49
+ # Note that you can return whatever content you want here,
50
+ # not only data from this object but also data from related objects, class names, etc.
51
+ posify do
52
+
53
+ # Only active instances should show up in search results.
54
+ return unless status == :active
55
+
56
+ # Return the fulltext content.
57
+ [ self.foo,
58
+ self.parent.bar,
59
+ self.children.map &:name ].join ' '
60
+ end
61
+ end
62
+ ```
55
63
 
56
64
 
57
65
  # Maintain the search index
@@ -60,53 +68,88 @@ The search index is automatically updated when Objects are saved or deleted.
60
68
 
61
69
  ## Indexing existing objects in the database
62
70
  If you had existing data in your database before adding Pose, it isn't automatically included in the search index.
63
- They will be added on the next save/update operation on them.
71
+ They will be added on the next save/update operation on them.
64
72
  You can also manually add existing objects to the search index.
65
73
 
66
- rake pose:reindex_all[MyClass]
74
+ ```bash
75
+ $ rake pose:reindex_all[MyClass]
76
+ ```
67
77
 
68
78
  ## Optimizing the search index
69
79
  The search index keeps all the words that were ever used around, in order to try to reuse them in the future.
70
80
  If you deleted a lot of objects, you can shrink the memory consumption of the search index by removing unused words.
71
81
 
72
- rake pose:cleanup_index
82
+ ```bash
83
+ $ rake pose:cleanup_index
84
+ ```
73
85
 
74
86
  ## Removing the search index
75
87
  For development purposes, or if something went wrong, you can remove the search index for a class
76
88
  (let's call it "MyClass") completely.
77
89
 
78
- rake pose:delete_index[MyClass]
90
+ ```bash
91
+ rake pose:delete_index[MyClass]
92
+ ```
79
93
 
80
94
 
81
95
  # Perform a search
82
96
 
83
- result = Pose.search 'foo', [MyClass, MyOtherClass]
97
+ ```ruby
98
+ result = Pose.search 'foo', [MyClass, MyOtherClass]
99
+ ```
84
100
 
85
101
  This searches for all instances of MyClass and MyOtherClass that contain the word 'foo'.
86
102
  The method returns a hash that looks like this:
87
103
 
88
- {
89
- MyClass => [ <myclass instance 1>, <myclass instance 2> ],
90
- MyOtherClass => [ ],
91
- }
92
-
104
+ ```ruby
105
+ {
106
+ MyClass => [ <myclass instance 1>, <myclass instance 2> ],
107
+ MyOtherClass => [ ],
108
+ }
109
+ ```
110
+
93
111
  In this example, it found two results of type _MyClass_ and no results of type _MyOtherClass_.
94
112
 
95
113
  Happy searching! :)
96
114
 
97
115
 
116
+ # Autocomplete support
117
+
118
+ Because the search index contains a list of all the words known to the search engine,
119
+ it can provide data for autocompletion functionality through the following convenience method:
120
+
121
+ ```ruby
122
+ # Returns an array of strings that start with 'cat'.
123
+ autocomplete_words = Pose.autocomplete_words 'cat'
124
+ ```
125
+
126
+ # Use Pose in your tests
127
+
128
+ By default, Pose doesn't run in Rails' test environment. This is to not slow down tests due to constant updating of the search index when objects are created.
129
+ If you want to test your models search functionality, you need to enable searching in tests:
130
+
131
+ ```ruby
132
+ Pose::CONFIGURATION[:search_in_tests] = true
133
+ ```
134
+
135
+ Please don't forget to set this value to `false` when you are done, or your remaining tests will be slow. A good place to enable/disable this flag is in before/after blocks of your test cases.
136
+
137
+
98
138
  # Development
99
139
 
100
- If you find a bug, have a question, or a better idea, please open an issue on the
101
- <a href="https://github.com/kevgo/pose/issues">Pose issue tracker</a>.
140
+ If you find a bug, have a question, or a better idea, please open an issue on the
141
+ <a href="https://github.com/kevgo/pose/issues">Pose issue tracker</a>.
102
142
  Or, clone the repository, make your changes, and submit a pull request.
103
143
 
104
- ## Unit Tests
144
+ ## Run the unit tests for the Pose Gem
145
+
146
+ ```bash
147
+ $ rake spec
148
+ ```
105
149
 
106
- rake spec
107
150
 
108
151
  ## Road Map
109
152
 
110
- Pose's algorithm works with all sorts of storage technologies that support range queries, i.e. relational databases,
153
+ Pose's algorithm works with all sorts of storage technologies that support range queries, i.e. relational databases,
111
154
  Google's DataStore, and other NoSQL stores. Right now, only relational databases are supported. NoSQL support is easy,
112
155
  but not yet implemented.
data/Rakefile CHANGED
@@ -9,18 +9,6 @@ require 'rspec/core/rake_task'
9
9
 
10
10
  Bundler::GemHelper.install_tasks
11
11
 
12
- desc 'Default: run the specs and features.'
13
- task :default => 'spec:unit' do
14
- system("bundle exec rake spec")
15
- end
16
-
17
- namespace :spec do
18
-
19
- desc "Run unit specs"
20
- RSpec::Core::RakeTask.new('unit') do |t|
21
- t.pattern = 'spec/{*_spec.rb}'
22
- end
23
- end
24
-
25
- desc "Run the unit tests"
26
- task :spec => ['spec:unit']
12
+ # RSpec tasks.
13
+ RSpec::Core::RakeTask.new :spec
14
+ task :default => :spec
@@ -0,0 +1,10 @@
1
+ module Pose
2
+ module BaseAdditions
3
+
4
+ def posify &block
5
+ include Pose::ModelAdditions
6
+ self.pose_content = block_given? ? block : :pose_content.to_proc
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,45 @@
1
+ # This Module contains code that gets added to classes that are posified.
2
+ module Pose
3
+ module ModelAdditions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_many :pose_assignments, :as => :posable, :dependent => :delete_all
8
+ has_many :pose_words, :through => :pose_assignments
9
+
10
+ after_save :update_pose_index
11
+ before_destroy :delete_pose_index
12
+
13
+ cattr_accessor :pose_content
14
+ end
15
+
16
+ # Updates the associated words for this object in the database.
17
+ def update_pose_index
18
+ update_pose_words if Pose.perform_search?
19
+ end
20
+
21
+ # Removes this objects from the search index.
22
+ def delete_pose_index
23
+ self.pose_words.clear if Pose.perform_search?
24
+ end
25
+
26
+ # Helper method.
27
+ # Updates the search words with the text returned by search_strings.
28
+ def update_pose_words
29
+
30
+ # Step 1: get an array of all words for the current object.
31
+ search_string = instance_eval &(self.class.pose_content)
32
+ new_words = search_string.to_s.split(' ').map { |word| Pose.root_word(word) }.flatten.uniq
33
+
34
+ # Step 2: Add new words to the search index.
35
+ Pose.get_words_to_add(self.pose_words, new_words).each do |word_to_add|
36
+ self.pose_words << PoseWord.find_or_create_by_text(word_to_add)
37
+ end
38
+
39
+ # Step 3: Remove now obsolete words from search index.
40
+ Pose.get_words_to_remove(self.pose_words, new_words).each do |word_to_remove|
41
+ self.pose_words.delete word_to_remove
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/pose/railtie.rb CHANGED
@@ -3,6 +3,15 @@ require "rails/railtie"
3
3
  module Pose
4
4
 
5
5
  class Railtie < Rails::Railtie
6
+
7
+ # Add the Pose additions to ActiveRecord::Base once it is loaded.
8
+ initializer 'Pose.base_additions' do
9
+ ActiveSupport.on_load :active_record do
10
+ extend Pose::BaseAdditions
11
+ end
12
+ end
13
+
14
+ # Load the Pose rake tasks.
6
15
  rake_tasks do
7
16
  load "tasks/pose_tasks.rake"
8
17
  end
@@ -0,0 +1,139 @@
1
+ # Static helper methods of the Pose gem.
2
+ module Pose
3
+ extend ActiveSupport::Concern
4
+
5
+ # By default, doesn't run in tests.
6
+ # Set this to true to test the search functionality.
7
+ CONFIGURATION = { :search_in_tests => false }
8
+
9
+ class <<self
10
+
11
+ # Asks if model should perform search.
12
+ #
13
+ # @return [false, true]
14
+ def perform_search?
15
+ !(Rails.env == 'test' and !CONFIGURATION[:search_in_tests])
16
+ end
17
+
18
+ # Returns all words that begin with the given query string.
19
+ # This can be used for autocompletion functionality.
20
+ #
21
+ # @param [String]
22
+ # @return [Array<String>]
23
+ def autocomplete_words query
24
+ return [] if query.blank?
25
+ PoseWord.where('text LIKE ?', "#{Pose.root_word(query)[0]}%").map(&:text)
26
+ end
27
+
28
+ # Returns all strings that are in new_words, but not in existing_words.
29
+ # Helper method.
30
+ #
31
+ # @param [Array<String>] existing_words The words that are already associated with the object.
32
+ # @param [Array<String>] new_words The words thet the object should have from now on.
33
+ #
34
+ # @return [Array<String>] The words that need to be added to the existing_words array.
35
+ def get_words_to_add existing_words, new_words
36
+ new_words - existing_words.map(&:text)
37
+ end
38
+
39
+ # Helper method.
40
+ # Returns the id of all word objects that are in existing_words, but not in new_words.
41
+ #
42
+ # @param [Array<String>] existing_words The words that are already associated with the object.
43
+ # @param [Array<String>] new_words The words thet the object should have from now on.
44
+ #
45
+ # @return [Array<String>] The words that need to be removed from the existing_words array.
46
+ def get_words_to_remove existing_words, new_words
47
+ existing_words.map do |existing_word|
48
+ existing_word unless new_words.include?(existing_word.text)
49
+ end.compact
50
+ end
51
+
52
+ # Returns whether the given string is a URL.
53
+ #
54
+ # @param [String] word The string to check.
55
+ #
56
+ # @return [Boolean]
57
+ def is_url? word
58
+ URI::parse(word).scheme == 'http'
59
+ rescue URI::InvalidURIError
60
+ false
61
+ end
62
+
63
+ # Simplifies the given word to a generic search form.
64
+ #
65
+ # @param [String] raw_word The word to make searchable.
66
+ #
67
+ # @return [String] The stemmed version of the word.
68
+ def root_word raw_word
69
+ result = []
70
+ raw_word_copy = raw_word[0..-1]
71
+ raw_word_copy.gsub! '%20', ' '
72
+ raw_word_copy.gsub! /[()*<>'",;\?\-\=&%#]/, ' '
73
+ raw_word_copy.gsub! /\s+/, ' '
74
+ raw_word_copy.split(' ').each do |word|
75
+ if Pose.is_url?(word)
76
+ result.concat word.split(/[\.\/\:]/).delete_if(&:blank?)
77
+ else
78
+ word.gsub! /[\-\/\._:]/, ' '
79
+ word.gsub! /\s+/, ' '
80
+ word.split(' ').each do |w|
81
+ stemmed_word = w.parameterize.singularize
82
+ result.concat stemmed_word.split ' '
83
+ end
84
+ end
85
+ end
86
+ result.uniq
87
+ end
88
+
89
+ # Returns all objects matching the given query.
90
+ #
91
+ # @param [String] query
92
+ # @param (Class|[Array<Class>]) classes
93
+ # @param [Number?] limit Optional limit.
94
+ #
95
+ # @return [Hash<Class, ActiveRecord::Relation>]
96
+ def search query, classes, limit = nil
97
+
98
+ # Turn 'classes' into an array.
99
+ classes = [classes].flatten
100
+ classes_names = classes.map &:name
101
+ classes_names = classes_names[0] if classes_names.size == 1
102
+
103
+ # Get the ids of the results.
104
+ result_classes_and_ids = {}
105
+ query.split(' ').each do |query_word|
106
+ current_word_classes_and_ids = {}
107
+ classes.each { |clazz| current_word_classes_and_ids[clazz.name] = [] }
108
+ query = PoseAssignment.joins(:pose_word) \
109
+ .where('pose_words.text LIKE ?', "#{query_word}%") \
110
+ .where('posable_type IN (?)', classes_names)
111
+ query.each do |pose_assignment|
112
+ current_word_classes_and_ids[pose_assignment.posable_type] << pose_assignment.posable_id
113
+ end
114
+
115
+ current_word_classes_and_ids.each do |class_name, ids|
116
+ if result_classes_and_ids.has_key? class_name
117
+ result_classes_and_ids[class_name] = result_classes_and_ids[class_name] & ids
118
+ else
119
+ result_classes_and_ids[class_name] = ids
120
+ end
121
+ end
122
+ end
123
+
124
+ # Load the results by id.
125
+ {}.tap do |result|
126
+ result_classes_and_ids.each do |class_name, ids|
127
+ result_class = Kernel.const_get class_name
128
+
129
+ if ids.any? && classes.include?(result_class)
130
+ ids = ids.slice(0, limit) if limit
131
+ result[result_class] = result_class.where :id => ids
132
+ else
133
+ result[result_class] = []
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
data/lib/pose/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pose
2
- VERSION = "0.3"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/pose.rb CHANGED
@@ -2,191 +2,9 @@
2
2
  require 'rake'
3
3
  include Rake::DSL if defined? Rake::DSL
4
4
 
5
-
6
- # Polymorphic search for ActiveRecord objects.
7
- module Pose
8
- extend ActiveSupport::Concern
9
-
10
- # By default, doesn't run in tests.
11
- # Set this to true to test the search functionality.
12
- CONFIGURATION = { :search_in_tests => false }
13
-
14
- included do
15
- has_many :pose_assignments, :as => :posable, :dependent => :delete_all
16
- has_many :pose_words, :through => :pose_assignments
17
-
18
- after_save :update_pose_index
19
- before_destroy :delete_pose_index
20
-
21
- cattr_accessor :pose_content
22
- end
23
-
24
- # Asks if model should perform search.
25
- #
26
- # @return [false, true]
27
- def perform_search?
28
- !(Rails.env == 'test' and !CONFIGURATION[:search_in_tests])
29
- end
30
-
31
- module InstanceMethods
32
-
33
- # Updates the associated words for this object in the database.
34
- def update_pose_index
35
- update_pose_words if perform_search?
36
- end
37
-
38
- # Removes this objects from the search index.
39
- def delete_pose_index
40
- self.pose_words.clear if perform_search?
41
- end
42
-
43
- # Helper method.
44
- # Updates the search words with the text returned by search_strings.
45
- def update_pose_words
46
-
47
- # Step 1: get an array of all words for the current object.
48
- search_string = instance_eval &(self.class.pose_content)
49
- new_words = search_string.to_s.split(' ').map { |word| Pose.root_word(word) }.flatten.uniq
50
-
51
- # Step 2: Add new words to the search index.
52
- Pose.get_words_to_add(self.pose_words, new_words).each do |word_to_add|
53
- self.pose_words << PoseWord.find_or_create_by_text(word_to_add)
54
- end
55
-
56
- # Step 3: Remove now obsolete words from search index.
57
- Pose.get_words_to_remove(self.pose_words, new_words).each do |word_to_remove|
58
- self.pose_words.delete word_to_remove
59
- end
60
- end
61
- end
62
-
63
- class <<self
64
-
65
- # Returns all words that begin with the given query string.
66
- # This can be used for autocompletion functionality.
67
- #
68
- # @param [String]
69
- # @return [Array<String>]
70
- def autocomplete_words query
71
- return [] if query.blank?
72
- PoseWord.where('text LIKE ?', "#{Pose.root_word(query)[0]}%").map(&:text)
73
- end
74
-
75
- # Returns all strings that are in new_words, but not in existing_words.
76
- # Helper method.
77
- #
78
- # @param [Array<String>] existing_words The words that are already associated with the object.
79
- # @param [Array<String>] new_words The words thet the object should have from now on.
80
- #
81
- # @return [Array<String>] The words that need to be added to the existing_words array.
82
- def get_words_to_add existing_words, new_words
83
- new_words - existing_words.map(&:text)
84
- end
85
-
86
- # Helper method.
87
- # Returns the id of all word objects that are in existing_words, but not in new_words.
88
- #
89
- # @param [Array<String>] existing_words The words that are already associated with the object.
90
- # @param [Array<String>] new_words The words thet the object should have from now on.
91
- #
92
- # @return [Array<String>] The words that need to be removed from the existing_words array.
93
- def get_words_to_remove existing_words, new_words
94
- existing_words.map do |existing_word|
95
- existing_word unless new_words.include?(existing_word.text)
96
- end.compact
97
- end
98
-
99
- # Returns whether the given string is a URL.
100
- #
101
- # @param [String] word The string to check.
102
- #
103
- # @return [Boolean]
104
- def is_url? word
105
- URI::parse(word).scheme == 'http'
106
- rescue URI::InvalidURIError
107
- false
108
- end
109
-
110
- # Simplifies the given word to a generic search form.
111
- #
112
- # @param [String] raw_word The word to make searchable.
113
- #
114
- # @return [String] The stemmed version of the word.
115
- def root_word raw_word
116
- result = []
117
- raw_word_copy = raw_word[0..-1]
118
- raw_word_copy.gsub! '%20', ' '
119
- raw_word_copy.gsub! /[()*<>'",;\?\-\=&%#]/, ' '
120
- raw_word_copy.gsub! /\s+/, ' '
121
- raw_word_copy.split(' ').each do |word|
122
- if Pose.is_url?(word)
123
- result.concat word.split(/[\.\/\:]/).delete_if(&:blank?)
124
- else
125
- word.gsub! /[\-\/\._:]/, ' '
126
- word.gsub! /\s+/, ' '
127
- word.split(' ').each do |w|
128
- stemmed_word = w.parameterize.singularize
129
- result.concat stemmed_word.split ' '
130
- end
131
- end
132
- end
133
- result.uniq
134
- end
135
-
136
- # Returns all objects matching the given query.
137
- #
138
- # @param [String] query
139
- # @param (Class|[Array<Class>]) classes
140
- # @param [Number?] limit Optional limit.
141
- #
142
- # @return [Hash<Class, ActiveRecord::Relation>]
143
- def search query, classes, limit = nil
144
-
145
- # Turn 'classes' into an array.
146
- classes = [classes].flatten
147
- classes_names = classes.map &:name
148
- classes_names = classes_names[0] if classes_names.size == 1
149
-
150
- # Get the ids of the results.
151
- result_classes_and_ids = {}
152
- query.split(' ').each do |query_word|
153
- current_word_classes_and_ids = {}
154
- classes.each { |clazz| current_word_classes_and_ids[clazz.name] = [] }
155
- query = PoseAssignment.joins(:pose_word) \
156
- .where('pose_words.text LIKE ?', "#{query_word}%") \
157
- .where('posable_type IN (?)', classes_names)
158
- query.each do |pose_assignment|
159
- current_word_classes_and_ids[pose_assignment.posable_type] << pose_assignment.posable_id
160
- end
161
-
162
- current_word_classes_and_ids.each do |class_name, ids|
163
- if result_classes_and_ids.has_key? class_name
164
- result_classes_and_ids[class_name] = result_classes_and_ids[class_name] & ids
165
- else
166
- result_classes_and_ids[class_name] = ids
167
- end
168
- end
169
- end
170
-
171
- # Load the results by id.
172
- {}.tap do |result|
173
- result_classes_and_ids.each do |class_name, ids|
174
- result_class = Kernel.const_get class_name
175
-
176
- if ids.any? && classes.include?(result_class)
177
- ids = ids.slice(0, limit) if limit
178
- result[result_class] = result_class.where :id => ids
179
- else
180
- result[result_class] = []
181
- end
182
- end
183
- end
184
- end
185
- end
186
- end
187
-
188
-
189
- require 'pose/posifier'
190
- require "pose/railtie" if defined? Rails
5
+ require 'pose/static_helpers'
6
+ require 'pose/base_additions'
7
+ require 'pose/model_additions'
8
+ require 'pose/railtie' if defined? Rails
191
9
  require 'pose_assignment'
192
10
  require 'pose_word'
data/spec/pose_spec.rb CHANGED
@@ -300,6 +300,14 @@ describe Pose do
300
300
  result.should include('green')
301
301
  end
302
302
 
303
+ it 'returns words that match the given phrase exactly' do
304
+ PoseWord.create :text => 'cat'
305
+
306
+ result = Pose.autocomplete_words 'cat'
307
+
308
+ result.should == ['cat']
309
+ end
310
+
303
311
  it 'stems the search query' do
304
312
  PosableOne.create :text => 'car'
305
313
 
data/spec/spec_helper.rb CHANGED
@@ -5,11 +5,8 @@ require 'bundler/setup'
5
5
  require 'hashie'
6
6
  require 'active_record'
7
7
  require 'active_support/core_ext/module/aliasing'
8
- require "pose"
9
- require 'pose_word.rb'
10
- require 'pose_assignment.rb'
11
- require "pose/posifier.rb"
12
8
  require 'active_support/core_ext/string'
9
+ require 'pose'
13
10
  require 'faker'
14
11
  require 'factory_girl'
15
12
  FactoryGirl.find_definitions
@@ -18,13 +15,11 @@ FactoryGirl.find_definitions
18
15
  ENV["RAILS_ENV"] = "test"
19
16
  Rails = Hashie::Mash.new({:env => 'test'})
20
17
 
21
-
22
- #require 'your_gem_name' # and any other gems you need
23
-
18
+ # We have no Railtie in these tests --> load Pose manually.
19
+ ActiveRecord::Base.send :extend, Pose::BaseAdditions
24
20
 
25
21
  # Load support files
26
22
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
27
- #Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
28
23
 
29
24
 
30
25
  RSpec.configure do |config|
@@ -52,6 +47,11 @@ RSpec.configure do |config|
52
47
  end
53
48
  end
54
49
 
50
+
51
+ #####################
52
+ # MATCHERS
53
+ #
54
+
55
55
  # Verifies that a taggable object has the given tags.
56
56
  RSpec::Matchers.define :have_pose_words do |expected|
57
57
  match do |actual|
@@ -70,6 +70,10 @@ RSpec::Matchers.define :have_pose_words do |expected|
70
70
  end
71
71
 
72
72
 
73
+ #####################
74
+ # TEST CLASSES
75
+ #
76
+
73
77
  class PosableOne < ActiveRecord::Base
74
78
  posify { text }
75
79
  end
@@ -78,6 +82,11 @@ class PosableTwo < ActiveRecord::Base
78
82
  posify { text }
79
83
  end
80
84
 
85
+
86
+ #####################
87
+ # DATABASE SETUP
88
+ #
89
+
81
90
  def setup_db
82
91
  ActiveRecord::Schema.define(:version => 1) do
83
92
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pose
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-08 00:00:00.000000000Z
12
+ date: 2012-03-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &70254153851040 !ruby/object:Gem::Requirement
16
+ requirement: &70121989270460 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70254153851040
24
+ version_requirements: *70121989270460
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70254153850260 !ruby/object:Gem::Requirement
27
+ requirement: &70121989278420 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70254153850260
35
+ version_requirements: *70121989278420
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: ruby-progressbar
38
- requirement: &70254153849780 !ruby/object:Gem::Requirement
38
+ requirement: &70121993362680 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70254153849780
46
+ version_requirements: *70121993362680
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: factory_girl
49
- requirement: &70254153848940 !ruby/object:Gem::Requirement
49
+ requirement: &70121993370180 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70254153848940
57
+ version_requirements: *70121993370180
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: faker
60
- requirement: &70254153848100 !ruby/object:Gem::Requirement
60
+ requirement: &70121993367740 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70254153848100
68
+ version_requirements: *70121993367740
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: hashie
71
- requirement: &70254153840100 !ruby/object:Gem::Requirement
71
+ requirement: &70121993380460 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70254153840100
79
+ version_requirements: *70121993380460
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70254153839240 !ruby/object:Gem::Requirement
82
+ requirement: &70121993397120 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70254153839240
90
+ version_requirements: *70121993397120
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: sqlite3
93
- requirement: &70254153838500 !ruby/object:Gem::Requirement
93
+ requirement: &70121993395560 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70254153838500
101
+ version_requirements: *70121993395560
102
102
  description: Pose ('Polymorphic Search') allows fulltext search for ActiveRecord objects.
103
103
  email:
104
104
  - kevin.goslar@gmail.com
@@ -127,8 +127,10 @@ files:
127
127
  - doc/top-level-namespace.html
128
128
  - lib/generators/pose_generator.rb
129
129
  - lib/generators/templates/migration.rb
130
- - lib/pose/posifier.rb
130
+ - lib/pose/base_additions.rb
131
+ - lib/pose/model_additions.rb
131
132
  - lib/pose/railtie.rb
133
+ - lib/pose/static_helpers.rb
132
134
  - lib/pose/version.rb
133
135
  - lib/pose.rb
134
136
  - lib/pose_assignment.rb
@@ -136,7 +138,7 @@ files:
136
138
  - lib/tasks/pose_tasks.rake
137
139
  - MIT-LICENSE
138
140
  - Rakefile
139
- - README.markdown
141
+ - README.md
140
142
  - spec/factories.rb
141
143
  - spec/pose_assignment_spec.rb
142
144
  - spec/pose_spec.rb
data/lib/pose/posifier.rb DELETED
@@ -1,13 +0,0 @@
1
- module Pose
2
- module Posifier
3
- extend ActiveSupport::Concern
4
-
5
- module ClassMethods
6
- def posify &block
7
- include Pose
8
- self.pose_content = block_given? ? block : :pose_content.to_proc
9
- end
10
- end
11
- end
12
- end
13
- ActiveRecord::Base.send :include, Pose::Posifier