mebla 1.0.0.rc2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mebla (1.0.0.rc1)
4
+ mebla (1.0.0.rc2)
5
5
  bson (= 1.2.0)
6
6
  bson_ext (= 1.2.0)
7
7
  mebla
data/README.md CHANGED
@@ -87,50 +87,26 @@ This will index all comments and make it available for searching directly throug
87
87
  Mebla supports two types of search, index search and model search; in index search Mebla searches
88
88
  the index and returns all matching documents regardless of their types, in model search however
89
89
  Mebla searches the index and returns matching documents of the model(s) type(s).
90
- documents
91
-
92
- Mebla performs search using [Slingshot's searching DSL](http://karmi.github.com/slingshot/), I encourage
93
- you to check the tutorial to have a broader view of slingshot's capabilities.
94
90
 
95
91
  #### Index searching
96
92
 
97
93
  Using the same models we defined above, we can search for all posts and comments with the author "cousine":
98
94
 
99
- Mebla.search do
100
- query do
101
- string "author: cousine"
102
- end
103
- end
95
+ Mebla.search "author: cousine"
104
96
 
105
97
  This will return all documents with an author set to "cousine" regardless of their type, if we however want to
106
98
  search only Posts and Comments, we would explicitly tell Mebla:
107
99
 
108
- Mebla.search [:post, :comment] do
109
- query { string "author: cousine" }
110
- end
111
-
112
- As shown above, you can also use the shorthand notation of ruby blocks.
100
+ Mebla.search "author: cousine", [:post, :comment]
113
101
 
114
102
  #### Model searching
115
103
 
116
104
  Instead of searching all models like index searching, we can search one model only:
117
105
 
118
- Post.search do
119
- query { string "title: Testing Search" }
120
-
121
- filter :term, :author => "cousine"
122
- filter :terms, :tags => ["ruby", "rails"]
123
-
124
- sort { publish_date "desc" }
125
-
126
- facet 'tags' do
127
- terms :tags, :global => true
128
- end
129
-
130
- facet 'authors' do
131
- terms :author
132
- end
133
- end
106
+ Post.search("title: Testing Search").desc(:publish_date).only(
107
+ :author => ["cousine"],
108
+ :tags => ["ruby", "rails"]
109
+ ).facet('tags', :tags, :global => true).facet('authors', :author)
134
110
 
135
111
  In the above example we are taking full advantage of slingshot's searching capabilities,
136
112
  we are getting all posts with the title "Testing Search", filtering the results with author
@@ -147,28 +123,14 @@ In the example above we are retrieving two facets, "tags" and "authors"; "tags"
147
123
  which means that we want to get the counts of posts for each tag over the whole index, "authors"
148
124
  however will only get the count of posts matching the search query for each author.
149
125
 
150
- You can find more about searching [here](http://karmi.github.com/slingshot/)
151
-
152
126
  #### Retrieving results
153
127
 
154
128
  To retrieve the results of the model search we performed above we would simply:
155
129
 
156
- hits = Post.search do
157
- query { string "title: Testing Search" }
158
-
159
- filter :term, :author => "cousine"
160
- filter :terms, :tags => ["ruby", "rails"]
161
-
162
- sort { publish_date "desc" }
163
-
164
- facet 'tags' do
165
- terms :tags, :global => true
166
- end
167
-
168
- facet 'authors' do
169
- terms :author
170
- end
171
- end
130
+ hits = Post.search("title: Testing Search").desc(:publish_date).only(
131
+ :author => ["cousine"],
132
+ :tags => ["ruby", "rails"]
133
+ ).facet('tags', :tags, :global => true).facet('authors', :author)
172
134
 
173
135
  hits.each do |hit|
174
136
  puts hit.title
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.rc2
1
+ 1.0.0
@@ -1,6 +1,6 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
- # @private
3
+ # Generates the required files for Mebla to function
4
4
  class InstallGenerator < Rails::Generators::Base
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
 
@@ -10,37 +10,26 @@ module Mebla
10
10
  end
11
11
 
12
12
  private
13
+ # Returns the rails application name
14
+ # @return [String]
13
15
  def app_name
14
16
  @app_name ||= defined_app_const_base? ? defined_app_name : File.basename(destination_root)
15
17
  end
16
18
 
19
+ # @private
20
+ # Returns the rails application name underscored
21
+ # @return [String]
17
22
  def defined_app_name
18
23
  defined_app_const_base.underscore
19
24
  end
20
25
 
26
+ # @private
27
+ # Returns the application CONSTANT
21
28
  def defined_app_const_base
22
29
  Rails.respond_to?(:application) && defined?(Rails::Application) &&
23
30
  Rails.application.is_a?(Rails::Application) && Rails.application.class.name.sub(/::Application$/, "")
24
- end
25
-
26
- alias :defined_app_const_base? :defined_app_const_base
27
-
28
- def app_const_base
29
- @app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, '_').squeeze('_').camelize
30
31
  end
31
32
 
32
- def app_const
33
- @app_const ||= "#{app_const_base}::Application"
34
- end
35
-
36
- def valid_app_const?
37
- if app_const =~ /^\d/
38
- raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
39
- elsif RESERVED_NAMES.include?(app_name)
40
- raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words."
41
- elsif Object.const_defined?(app_const_base)
42
- raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name."
43
- end
44
- end
33
+ alias :defined_app_const_base? :defined_app_const_base
45
34
  end
46
35
  end
@@ -1,7 +1,7 @@
1
1
  require 'erb'
2
2
  require 'singleton'
3
3
 
4
- # @private
4
+ # A wrapper for slingshot elastic-search adapter for Mongoid
5
5
  module Mebla
6
6
  # Parses the configuration file and holds important configuration attributes
7
7
  class Configuration
@@ -11,6 +11,7 @@ module Mebla
11
11
  attr_accessor :index, :host, :port, :logger
12
12
 
13
13
  # @private
14
+ # Initializes a new configuration object
14
15
  def initialize
15
16
  @log_dir = "#{Dir.pwd}/tmp/log"
16
17
  parse_config
@@ -21,10 +22,10 @@ module Mebla
21
22
  @port ||= 9200
22
23
 
23
24
  make_tmp_dir
24
- @logger = Logger.new(
25
+ @logger = ActiveSupport::BufferedLogger.new(
25
26
  open("#{@log_dir}/mebla.log", "a")
26
27
  )
27
- @logger.level = Logger::DEBUG
28
+ @logger.level = ActiveSupport::BufferedLogger::Severity::DEBUG
28
29
 
29
30
  setup_logger
30
31
 
@@ -35,10 +36,7 @@ module Mebla
35
36
  # Sets up the default settings of the logger
36
37
  # @return [nil]
37
38
  def setup_logger
38
- @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
39
- @logger.formatter = proc { |severity, datetime, progname, msg|
40
- "#{datetime}: #{msg}\n"
41
- }
39
+ @logger.auto_flushing = true
42
40
  end
43
41
 
44
42
  # Returns the proper url for elasticsearch
data/lib/mebla/context.rb CHANGED
@@ -1,4 +1,4 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
3
  # Handles indexing and reindexing
4
4
  class Context
@@ -6,6 +6,7 @@ module Mebla
6
6
  attr_reader :mappings
7
7
 
8
8
  # @private
9
+ # Creates a new context object
9
10
  def initialize
10
11
  @indexed_models = []
11
12
  @mappings = {}
@@ -30,9 +31,9 @@ module Mebla
30
31
  # @return [nil]
31
32
  def rebuild_index
32
33
  # Only rebuild if the index exists
33
- raise ::Mebla::Errors::MeblaIndexException.new("#{@slingshot_index_name} does not exist !! use #create_index to create the index first.") unless index_exists?
34
+ raise Mebla::Errors::MeblaIndexException.new("#{@slingshot_index_name} does not exist !! use #create_index to create the index first.") unless index_exists?
34
35
 
35
- ::Mebla.log("Rebuilding index")
36
+ Mebla.log("Rebuilding index")
36
37
 
37
38
  # Delete the index
38
39
  if drop_index
@@ -46,9 +47,9 @@ module Mebla
46
47
  # @return [Boolean] true if operation is successful
47
48
  def create_index
48
49
  # Only create the index if it doesn't exist
49
- raise ::Mebla::Errors::MeblaIndexException.new("#{@slingshot_index_name} already exists !! use #rebuild_index to rebuild the index.") if index_exists?
50
+ raise Mebla::Errors::MeblaIndexException.new("#{@slingshot_index_name} already exists !! use #rebuild_index to rebuild the index.") if index_exists?
50
51
 
51
- ::Mebla.log("Creating index")
52
+ Mebla.log("Creating index")
52
53
 
53
54
  # Create the index
54
55
  build_index
@@ -60,12 +61,12 @@ module Mebla
60
61
  # Only drop the index if it exists
61
62
  return true unless index_exists?
62
63
 
63
- ::Mebla.log("Dropping index: #{self.slingshot_index_name}", :debug)
64
+ Mebla.log("Dropping index: #{self.slingshot_index_name}", :debug)
64
65
 
65
66
  # Drop the index
66
67
  result = @slingshot_index.delete
67
68
 
68
- ::Mebla.log("Dropped #{self.slingshot_index_name}: #{result.to_s}", :debug)
69
+ Mebla.log("Dropped #{self.slingshot_index_name}: #{result.to_s}", :debug)
69
70
 
70
71
  # Check that the index doesn't exist
71
72
  !index_exists?
@@ -86,13 +87,13 @@ module Mebla
86
87
  # @param *models a list of symbols each representing a model name to be indexed
87
88
  # @return [nil]
88
89
  def index_data(*models)
89
- if models.empty?
90
+ if models.nil? || models.empty?
90
91
  only_index = @indexed_models
91
92
  else
92
93
  only_index = models.collect{|m| m.to_s}
93
94
  end
94
95
 
95
- ::Mebla.log("Indexing #{only_index.join(", ")}", :debug)
96
+ Mebla.log("Indexing #{only_index.join(", ")}", :debug)
96
97
 
97
98
  # Build up a bulk query to save processing and time
98
99
  bulk_query = ""
@@ -103,7 +104,7 @@ module Mebla
103
104
  if create_index
104
105
  # Start collecting documents
105
106
  only_index.each do |model|
106
- ::Mebla.log("Indexing: #{model}")
107
+ Mebla.log("Indexing: #{model}")
107
108
  # Get the class
108
109
  to_index = model.camelize.constantize
109
110
 
@@ -141,13 +142,10 @@ module Mebla
141
142
  end
142
143
  end
143
144
  else
144
- raise ::Mebla::Errors::MeblaIndexException.new("Could not create #{@slingshot_index_name}!!!")
145
- end
146
-
147
- # Add a new line to the query
148
- bulk_query << '\n'
145
+ raise Mebla::Errors::MeblaIndexException.new("Could not create #{@slingshot_index_name}!!!")
146
+ end
149
147
 
150
- ::Mebla.log("Bulk indexing:\n#{bulk_query}", :debug)
148
+ Mebla.log("Bulk indexing:\n#{bulk_query}", :debug)
151
149
 
152
150
  # Send the query
153
151
  response = Slingshot::Configuration.client.post "#{Mebla::Configuration.instance.url}/_bulk", bulk_query
@@ -155,54 +153,58 @@ module Mebla
155
153
  # Only refresh the index if no error ocurred
156
154
  unless response =~ /error/
157
155
  # Log results
158
- ::Mebla.log("Indexed #{only_index.count} model(s) to #{self.slingshot_index_name}: #{response}")
159
- ::Mebla.log("Indexing Report:")
156
+ Mebla.log("Indexed #{only_index.count} model(s) to #{self.slingshot_index_name}: #{response}")
157
+ Mebla.log("Indexing Report:")
160
158
  indexed_count.each do |model_name, count|
161
- ::Mebla.log("Indexed #{model_name}: #{count} document(s)")
159
+ Mebla.log("Indexed #{model_name}: #{count} document(s)")
162
160
  end
163
161
 
164
162
  # Refresh the index
165
163
  refresh_index
166
164
  else
167
- raise ::Mebla::Errors::MeblaIndexException.new("Indexing #{only_index.join(", ")} failed with the following response:\n #{response}")
165
+ raise Mebla::Errors::MeblaIndexException.new("Indexing #{only_index.join(", ")} failed with the following response:\n #{response}")
168
166
  end
169
167
  rescue RestClient::Exception => error
170
- raise ::Mebla::Errors::MeblaIndexException.new("Indexing #{only_index.join(", ")} failed with the following error: #{error.message}")
168
+ raise Mebla::Errors::MeblaIndexException.new("Indexing #{only_index.join(", ")} failed with the following error: #{error.message}")
171
169
  end
172
170
 
173
171
  # Rebuilds the index and indexes the data for all models or a list of models given
174
172
  # @param *models a list of symbols each representing a model name to rebuild it's index
175
173
  # @return [nil]
176
174
  def reindex_data(*models)
177
- ::Mebla.log("Rendexing: #{self.slingshot_index_name}")
175
+ Mebla.log("Rendexing: #{self.slingshot_index_name}")
178
176
 
179
177
  unless drop_index
180
- raise ::Mebla::Errors::MeblaIndexException.new("Could not drop #{@slingshot_index_name}!!!")
178
+ raise Mebla::Errors::MeblaIndexException.new("Could not drop #{@slingshot_index_name}!!!")
181
179
  end
182
180
 
183
181
  # Create the index and index the data
184
- index_data(models)
182
+ if models && !models.empty?
183
+ index_data(models)
184
+ else
185
+ index_data
186
+ end
185
187
  end
186
188
 
187
189
  # Refreshes the index
188
190
  # @return [nil]
189
191
  def refresh_index
190
- ::Mebla.log("Refreshing: #{self.slingshot_index_name}", :debug)
192
+ Mebla.log("Refreshing: #{self.slingshot_index_name}", :debug)
191
193
 
192
194
  result = @slingshot_index.refresh
193
195
 
194
- ::Mebla.log("Refreshed #{self.slingshot_index_name}: #{result}")
196
+ Mebla.log("Refreshed #{self.slingshot_index_name}: #{result}")
195
197
  end
196
198
 
197
199
  private
198
200
  # Builds the index according to the mappings set
199
201
  # @return [Boolean] true if the index was created successfully, false otherwise
200
202
  def build_index
201
- ::Mebla.log("Building index", :debug)
203
+ Mebla.log("Building #{self.slingshot_index_name}", :debug)
202
204
  # Create the index
203
205
  result = @slingshot_index.create :mappings => @mappings
204
206
 
205
- ::Mebla.log("Created index: #{result.to_s}")
207
+ Mebla.log("Created #{self.slingshot_index_name}: #{result.to_s}")
206
208
 
207
209
  # Check if the index exists
208
210
  index_exists?
@@ -1,6 +1,6 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
- # @private
3
+ # Represents the parent module for all errors in Mebla
4
4
  module Errors
5
5
  # Thrown when configuration fails
6
6
  # @note this is a fatal exception
@@ -1,6 +1,6 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
- # @private
3
+ # Represents the parent module for all errors in Mebla
4
4
  module Errors
5
5
  # Default parent Mebla error for all custom non-fatal errors.
6
6
  class MeblaError < ::StandardError
@@ -1,6 +1,6 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
- # @private
3
+ # Represents the parent module for all errors in Mebla
4
4
  module Errors
5
5
  # Default parent Mebla error for all custom fatal errors.
6
6
  class MeblaFatal < ::StandardError
@@ -1,6 +1,6 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
- # @private
3
+ # Represents the parent module for all errors in Mebla
4
4
  module Errors
5
5
  # Thrown when an index operation fails
6
6
  # @note this is a fatal exception
@@ -1,6 +1,6 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
- # @private
3
+ # Represents the parent module for all errors in Mebla
4
4
  module Errors
5
5
  # Thrown when a synchronization operation fails
6
6
  class MeblaSynchronizationException < MeblaError
@@ -0,0 +1,11 @@
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
+ module Mebla
3
+ # Represents the parent module for all errors in Mebla
4
+ module Errors
5
+ autoload :MeblaError, 'mebla/errors/mebla_error'
6
+ autoload :MeblaFatal, 'mebla/errors/mebla_fatal'
7
+ autoload :MeblaConfigurationException, 'mebla/errors/mebla_configuration_exception'
8
+ autoload :MeblaIndexException, 'mebla/errors/mebla_index_exception'
9
+ autoload :MeblaSynchronizationException, 'mebla/errors/mebla_synchronization_exceptions'
10
+ end
11
+ end
@@ -1,6 +1,6 @@
1
1
  require 'active_support/log_subscriber'
2
2
 
3
- # @private
3
+ # A wrapper for slingshot elastic-search adapter for Mongoid
4
4
  module Mebla
5
5
  # Handles logging
6
6
  class LogSubscriber < ActiveSupport::LogSubscriber
@@ -11,27 +11,27 @@ module Mebla
11
11
 
12
12
  # Error message
13
13
  def mebla_error(event)
14
- error_red event.payload[:message]
14
+ error_red event.payload[:message]
15
15
  end
16
16
 
17
17
  # Info message
18
18
  def mebla_info(event)
19
- info_blue event.payload[:message]
19
+ info_blue event.payload[:message]
20
20
  end
21
21
 
22
22
  # Fatal message
23
23
  def mebla_fatal(event)
24
- fatal_magenta event.payload[:message]
24
+ fatal_magenta event.payload[:message]
25
25
  end
26
26
 
27
27
  # Warning message
28
28
  def mebla_warn(event)
29
- warn_yellow event.payload[:message]
29
+ warn_yellow event.payload[:message]
30
30
  end
31
31
 
32
- # Unkown message
33
- def mebla_unkown(event)
34
- unkown event.payload[:message]
32
+ # Unknown message
33
+ def mebla_unknown(event)
34
+ unknown event.payload[:message]
35
35
  end
36
36
 
37
37
  # --
@@ -42,7 +42,7 @@ module Mebla
42
42
 
43
43
  # Print a debug message to the log file
44
44
  def debug_green(msg)
45
- debug color(msg, LogSubscriber::Green)
45
+ debug color(msg, LogSubscriber::GREEN)
46
46
  end
47
47
 
48
48
  # Print an error message to the log file
@@ -52,7 +52,7 @@ module Mebla
52
52
 
53
53
  # Print an info message to the log file
54
54
  def info_blue(msg)
55
- ingo color(msg, LogSubscriber::BLUE)
55
+ info color(msg, LogSubscriber::BLUE)
56
56
  end
57
57
 
58
58
  # Print a fatal message to the log file
@@ -67,11 +67,8 @@ module Mebla
67
67
 
68
68
  # Returns the main logger for Mebla
69
69
  # @return [Logger]
70
- def logger
70
+ def self.logger
71
71
  Mebla::Configuration.instance.logger
72
72
  end
73
73
  end
74
- end
75
-
76
- # Register the logger
77
- Mebla::LogSubscriber.attach_to :mebla
74
+ end
@@ -42,6 +42,7 @@ module Mongoid
42
42
  self.whiny_indexing = false
43
43
  end
44
44
 
45
+ # Defines class methods for Mongoid::Mebla
45
46
  module ClassMethods
46
47
  # Defines which fields should be indexed and searched
47
48
  # @param [*opts] fields
@@ -123,20 +124,15 @@ module Mongoid
123
124
  ::Mebla.context.add_indexed_model(self, self.slingshot_type_name.to_sym => prepare_mappings)
124
125
  end
125
126
 
126
- # Searches the model using Slingshot search DSL
127
- # @return [ResultSet]
127
+ # Searches the model using Slingshot search DSL
128
+ # @param [String] query a string representing the search query
129
+ # @return [Mebla::Search]
128
130
  #
129
- # Search for posts with the title 'Testing Search'::
131
+ # Search for all posts with a field 'title' of value 'Testing Search'::
130
132
  #
131
- # Post.search do
132
- # query do
133
- # string "title: Testing Search"
134
- # end
135
- # end
136
- #
137
- # @note For more information about Slingshot search DSL, check http://karmi.github.com/slingshot
138
- def search(&block)
139
- ::Mebla.search(self.slingshot_type_name, &block)
133
+ # Post.search "title: Testing Search"
134
+ def search(query = "")
135
+ ::Mebla.search(query, self.slingshot_type_name)
140
136
  end
141
137
 
142
138
  # Retrieves the type name of the model
@@ -244,6 +240,7 @@ module Mongoid
244
240
  return false
245
241
  end
246
242
 
243
+ # Raises synchronization exception in either #add_to_index or #remove_from_index
247
244
  def raise_synchronization_exception(error)
248
245
  exception_message = "#{self.class.slingshot_type_name} synchronization failed with the following error: #{error.message}"
249
246
  if self.class.whiny_indexing
data/lib/mebla/railtie.rb CHANGED
@@ -1,34 +1,35 @@
1
1
  require 'mebla'
2
2
  require 'rails'
3
3
 
4
- # @private
4
+ # A wrapper for slingshot elastic-search adapter for Mongoid
5
5
  module Mebla
6
6
  # @private
7
+ # Railtie for Mebla
7
8
  class Railtie < Rails::Railtie
8
9
  # Configuration
9
10
  initializer "mebla.set_configs" do |app|
10
11
  Mebla.configure do |config|
11
12
  # Open logfile
12
- config.logger = Logger.new(
13
- open("#{Dir.pwd}/logs/#{Rails.env}.mebla.log", "a")
13
+ config.logger = ActiveSupport::BufferedLogger.new(
14
+ open("#{Dir.pwd}/log/#{Rails.env}.mebla.log", "a")
14
15
  )
15
16
  # Setup the log level
16
17
  config.logger.level = case app.config.log_level
17
18
  when :info
18
- Logger::INFO
19
+ ActiveSupport::BufferedLogger::Severity::INFO
19
20
  when :warn
20
- Logger::WARN
21
+ ActiveSupport::BufferedLogger::Severity::WARN
21
22
  when :error
22
- Logger::ERROR
23
+ ActiveSupport::BufferedLogger::Severity::ERROR
23
24
  when :fatal
24
- Logger::FATAL
25
+ ActiveSupport::BufferedLogger::Severity::FATAL
25
26
  else
26
- Logger::DEBUG
27
+ ActiveSupport::BufferedLogger::Severity::DEBUG
27
28
  end
28
29
 
29
30
  config.setup_logger
30
31
  end
31
- end
32
+ end
32
33
 
33
34
  # Rake tasks
34
35
  rake_tasks do
@@ -1,4 +1,4 @@
1
- # @private
1
+ # A wrapper for slingshot elastic-search adapter for Mongoid
2
2
  module Mebla
3
3
  # Represents a set of search results
4
4
  class ResultSet
@@ -14,8 +14,8 @@ module Mebla
14
14
  def initialize(response)
15
15
  # Keep the query time
16
16
  @time = response['took']
17
- # Keep the facets
18
- @facets = response['facets']
17
+ # Keep the facets
18
+ @facets = response['facets']
19
19
  # Keep the query total to check against the count
20
20
  @total = response['hits']['total']
21
21