mebla 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,6 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
6
+ TODO.md
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in Rakefile
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mebla (1.0.0.rc1)
5
+ bson (= 1.2.0)
6
+ bson_ext (= 1.2.0)
7
+ mebla
8
+ mongoid (= 2.0.0.rc.7)
9
+ slingshot-rb (~> 0.0.6)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ activemodel (3.0.5)
15
+ activesupport (= 3.0.5)
16
+ builder (~> 2.1.2)
17
+ i18n (~> 0.4)
18
+ activesupport (3.0.5)
19
+ bluecloth (2.1.0)
20
+ bson (1.2.0)
21
+ bson_ext (1.2.0)
22
+ builder (2.1.2)
23
+ database_cleaner (0.6.4)
24
+ diff-lcs (1.1.2)
25
+ git (1.2.5)
26
+ i18n (0.5.0)
27
+ jeweler (1.5.2)
28
+ bundler (~> 1.0.0)
29
+ git (>= 1.2.5)
30
+ rake
31
+ mime-types (1.16)
32
+ mongo (1.2.0)
33
+ bson (>= 1.2.0)
34
+ mongoid (2.0.0.rc.7)
35
+ activemodel (~> 3.0)
36
+ mongo (~> 1.2)
37
+ tzinfo (~> 0.3.22)
38
+ will_paginate (~> 3.0.pre)
39
+ mongoid-rspec (1.4.1)
40
+ mongoid (~> 2.0.0.rc.7)
41
+ mongoid-rspec
42
+ rspec (~> 2)
43
+ rake (0.8.7)
44
+ rcov (0.9.9)
45
+ rest-client (1.6.1)
46
+ mime-types (>= 1.16)
47
+ rspec (2.3.0)
48
+ rspec-core (~> 2.3.0)
49
+ rspec-expectations (~> 2.3.0)
50
+ rspec-mocks (~> 2.3.0)
51
+ rspec-core (2.3.1)
52
+ rspec-expectations (2.3.0)
53
+ diff-lcs (~> 1.1.2)
54
+ rspec-mocks (2.3.0)
55
+ slingshot-rb (0.0.6)
56
+ bundler (~> 1.0.0)
57
+ rest-client (~> 1.6.0)
58
+ yajl-ruby (> 0.7.9)
59
+ tzinfo (0.3.24)
60
+ will_paginate (3.0.pre2)
61
+ yajl-ruby (0.8.1)
62
+ yard (0.6.4)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ bluecloth (~> 2.1.0)
69
+ bson (= 1.2.0)
70
+ bson_ext (= 1.2.0)
71
+ bundler (~> 1.0.0)
72
+ database_cleaner (= 0.6.4)
73
+ jeweler (~> 1.5.2)
74
+ mebla!
75
+ mongoid (= 2.0.0.rc.7)
76
+ mongoid-rspec (= 1.4.1)
77
+ rcov
78
+ rspec (~> 2.3.0)
79
+ yard (~> 0.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Omar Mekky
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,250 @@
1
+ Mebla
2
+ ====
3
+
4
+ Mebla is an [elasticsearch](http://www.elasticsearch.org) wrapper for [Mongoid](http://mongoid.org) based on
5
+ [Slingshot](https://github.com/karmi/slingshot).
6
+
7
+ Name
8
+ ---------
9
+
10
+ Mebla is derived from the word "Nebla", which means slingshot in arabic.
11
+
12
+ Also since its a wrapper for mongoid ODM, the letter "N" is replaced with "M".
13
+
14
+ Installation
15
+ ---------------
16
+
17
+ ### Install elasticsearch
18
+
19
+ Mebla requires a running [elasticsearch](http://www.elasticsearch.org) installation.
20
+
21
+ To install elasticsearch follow the uptodate instructions [here](http://www.elasticsearch.org/guide/reference/setup/) or
22
+ simply copy and paste in your terminal window:
23
+
24
+ $ curl -k -L -o elasticsearch-0.15.0.tar.gz http://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.15.0.tar.gz
25
+ $ tar -zxvf elasticsearch-0.15.0.tar.gz
26
+ $ ./elasticsearch-0.15.0/bin/elasticsearch -f
27
+
28
+ ### Install Mebla
29
+
30
+ Once elasticsearch is installed, add Mebla to your gem file:
31
+
32
+ gem "mebla"
33
+
34
+ then run bundle in your application root to update your gems' bundle:
35
+
36
+ $ bundle install
37
+
38
+ next generate the configuration file:
39
+
40
+ $ rails generate mebla:install
41
+
42
+ finally index your data:
43
+
44
+ $ rake mebla:index_data
45
+
46
+ Usage
47
+ ---------
48
+
49
+ ### Defining indexed fields
50
+
51
+ To enable searching models, you first have to define which fields mebla should index:
52
+
53
+ class Post
54
+ include Mongoid::Document
55
+ include Mongoid::Mebla
56
+ field :title
57
+ field :author
58
+ field :body
59
+ field :publish_date, :type => Date
60
+ field :tags, :type => Array
61
+
62
+ embeds_many :comments
63
+ search_in :author, :body, :publish_date, :tags, :title => { :boost => 2.0, :analyzer => 'snowball' }
64
+ end
65
+
66
+ In the example above, mebla will index the author field, body field, publish_date field and finally indexes
67
+ the title field with some custom [mappings](http://www.elasticsearch.org/guide/reference/mapping).
68
+
69
+ #### Embedded documents
70
+
71
+ You can also index embedded documents as follows:
72
+
73
+ class Comment
74
+ include Mongoid::Document
75
+ include Mongoid::Mebla
76
+ field :comment
77
+ field :author
78
+
79
+ embedded_in :blog_post
80
+ search_in :comment, :author, :embedded_in => :blog_post
81
+ end
82
+
83
+ This will index all comments and make it available for searching directly through the Comment model.
84
+
85
+ ### Searching the index
86
+
87
+ Mebla supports two types of search, index search and model search; in index search Mebla searches
88
+ the index and returns all matching documents regardless of their types, in model search however
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
+
95
+ #### Index searching
96
+
97
+ Using the same models we defined above, we can search for all posts and comments with the author "cousine":
98
+
99
+ Mebla.search do
100
+ query do
101
+ string "author: cousine"
102
+ end
103
+ end
104
+
105
+ This will return all documents with an author set to "cousine" regardless of their type, if we however want to
106
+ search only Posts and Comments, we would explicitly tell Mebla:
107
+
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.
113
+
114
+ #### Model searching
115
+
116
+ Instead of searching all models like index searching, we can search one model only:
117
+
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
134
+
135
+ In the above example we are taking full advantage of slingshot's searching capabilities,
136
+ we are getting all posts with the title "Testing Search", filtering the results with author
137
+ "cousine", tagged "ruby" or "rails", and sorting the results with their publish_date fields.
138
+
139
+ One more feature we are using is "Faceted Search", from Slingshot's homepage:
140
+
141
+ > _Faceted Search_
142
+ >
143
+ > _ElasticSearch makes it trivial to retrieve complex aggregated data from the index/database, so called
144
+ [facets](http://www.lucidimagination.com/Community/Hear-from-the-Experts/Articles/Faceted-Search-Solr)._
145
+
146
+ In the example above we are retrieving two facets, "tags" and "authors"; "tags" are global
147
+ which means that we want to get the counts of posts for each tag over the whole index, "authors"
148
+ however will only get the count of posts matching the search query for each author.
149
+
150
+ You can find more about searching [here](http://karmi.github.com/slingshot/)
151
+
152
+ #### Retrieving results
153
+
154
+ To retrieve the results of the model search we performed above we would simply:
155
+
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
172
+
173
+ hits.each do |hit|
174
+ puts hit.title
175
+ end
176
+
177
+ To retrieve the facets:
178
+
179
+ # Get the count of posts for each tag accross the index
180
+ hits.facets['tags']['terms'].each do |facet|
181
+ puts "#{facet['term']} : #{facet['count']}"
182
+ end
183
+
184
+ # Get the count of posts matching the query for each author
185
+ hits.facets['authors']['terms'].each do |facet|
186
+ puts "#{facet['term']} : #{facet['count']}"
187
+ end
188
+
189
+ ### Indexing data
190
+
191
+ #### Synchronizing data
192
+
193
+ By default Mebla synchronizes all changes done to your models with your index, if however
194
+ you would like to bypass this behavior:
195
+
196
+ Post.without_indexing do
197
+ Post.create :title => "This won't be indexed"
198
+ end
199
+
200
+ #### Indexing existing data
201
+
202
+ You can index existing data by using the "index" rake task:
203
+
204
+ $ rake mebla:index
205
+
206
+ This will create the index and index all the data in the database
207
+
208
+ #### Reindexing
209
+
210
+ Just like indexing, you can reindex your data using the "reindex" rake task:
211
+
212
+ $ rake mebla:reindex
213
+
214
+ This will rebuild the index and index all your data again, note that unlike other full-text
215
+ search engines, you don't need to reindex your data frequently (if ever) however you
216
+ might want to refresh the index so changes are reflected on the index.
217
+
218
+ #### Refreshing the index
219
+
220
+ Refreshing the index makes changes done to the index available for searching or modification.
221
+
222
+ Mebla automatically refreshes the index whenever a change is done, but just incase you
223
+ need to refresh the index:
224
+
225
+ $ rake mebla:refresh
226
+
227
+ ### Rake tasks
228
+
229
+ Mebla provides a number of rake tasks to perform various tasks on the index, you can
230
+ list all tasks using this command:
231
+
232
+ $ rake -T mebla
233
+
234
+ Contributing to Mebla
235
+ ----------------------------
236
+
237
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
238
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
239
+ * Fork the project
240
+ * Start a feature/bugfix branch
241
+ * Commit and push until you are happy with your contribution
242
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
243
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
244
+
245
+ Copyright
246
+ -------------
247
+
248
+ Copyright (c) 2011 Omar Mekky. See LICENSE.txt for
249
+ further details.
250
+
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "mebla"
16
+ gem.homepage = "http://github.com/cousine/mebla"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{An elasticsearch wrapper for mongoid odm based on slingshot.}
19
+ gem.description = %Q{
20
+ An elasticsearch wrapper for mongoid odm based on slingshot. Makes integration between ElasticSearch full-text
21
+ search engine and Mongoid documents seemless and simple.
22
+ }
23
+ gem.email = "omar.mekky@mashsolvents.com"
24
+ gem.authors = ["Omar Mekky"]
25
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
26
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
27
+ gem.add_runtime_dependency 'slingshot-rb', '~> 0.0.6'
28
+ gem.add_runtime_dependency 'mongoid', '2.0.0.rc.7'
29
+ gem.add_runtime_dependency 'bson', '1.2.0'
30
+ gem.add_runtime_dependency 'bson_ext', '1.2.0'
31
+
32
+ gem.add_development_dependency 'rspec', '~> 2.3.0'
33
+ gem.add_development_dependency 'yard', '~> 0.6.0'
34
+ gem.add_development_dependency 'bundler', '~> 1.0.0'
35
+ gem.add_development_dependency 'jeweler', '~> 1.5.2'
36
+ gem.add_development_dependency 'rcov', '>= 0'
37
+ gem.add_development_dependency 'mongoid-rspec', '1.4.1'
38
+ gem.add_development_dependency 'database_cleaner', '0.6.4'
39
+ gem.add_development_dependency 'bluecloth', '~> 2.1.0'
40
+ end
41
+ Jeweler::RubygemsDotOrgTasks.new
42
+
43
+ require 'rspec/core'
44
+ require 'rspec/core/rake_task'
45
+ RSpec::Core::RakeTask.new(:spec) do |spec|
46
+ spec.pattern = FileList['spec/**/*_spec.rb']
47
+ end
48
+
49
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
50
+ spec.pattern = 'spec/**/*_spec.rb'
51
+ spec.rcov = true
52
+ end
53
+
54
+ task :default => :spec
55
+
56
+ require 'yard'
57
+ YARD::Rake::YardocTask.new
data/TODO.md ADDED
@@ -0,0 +1,12 @@
1
+ TODO for version 1.0.0
2
+ ==============
3
+
4
+ * <strike>add documentation for mebla in README.md</strike>
5
+ * <strike>add logging capabilities</strike>
6
+
7
+ Future plan
8
+ =======
9
+
10
+ * add ability to index embedded documents (as part of the parent document)
11
+ * optimize : should find a solution for not refreshing the index while indexing embedded documents in lib/mebla/context
12
+ * optimize : refractor result_set
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0.rc2
@@ -0,0 +1,7 @@
1
+ Description:
2
+ Generates mebla's configuration file.
3
+
4
+ Example:
5
+ rails generate mebla:install
6
+
7
+ This will generate mebla's configuration file in config folder
@@ -0,0 +1,46 @@
1
+ # @private
2
+ module Mebla
3
+ # @private
4
+ class InstallGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+ # Generates mebla's configuration file
8
+ def generate_configuration
9
+ template "mebla.yml", "config/mebla.yml"
10
+ end
11
+
12
+ private
13
+ def app_name
14
+ @app_name ||= defined_app_const_base? ? defined_app_name : File.basename(destination_root)
15
+ end
16
+
17
+ def defined_app_name
18
+ defined_app_const_base.underscore
19
+ end
20
+
21
+ def defined_app_const_base
22
+ Rails.respond_to?(:application) && defined?(Rails::Application) &&
23
+ 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
+ end
31
+
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
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ defaults: &defaults
2
+ host: localhost
3
+ port: 9200
4
+
5
+ development:
6
+ <<: *defaults
7
+ index: <%= app_name %>_development
8
+
9
+ test:
10
+ <<: *defaults
11
+ index: <%= app_name %>_test
12
+
13
+ production:
14
+ <<: *defaults
15
+ index: <%= app_name %>_production
@@ -0,0 +1,73 @@
1
+ require 'erb'
2
+ require 'singleton'
3
+
4
+ # @private
5
+ module Mebla
6
+ # Parses the configuration file and holds important configuration attributes
7
+ class Configuration
8
+ include Singleton
9
+
10
+ attr_reader :log_dir
11
+ attr_accessor :index, :host, :port, :logger
12
+
13
+ # @private
14
+ def initialize
15
+ @log_dir = "#{Dir.pwd}/tmp/log"
16
+ parse_config
17
+
18
+ # Setup defaults
19
+ @index ||= "mebla"
20
+ @host ||= "localhost"
21
+ @port ||= 9200
22
+
23
+ make_tmp_dir
24
+ @logger = Logger.new(
25
+ open("#{@log_dir}/mebla.log", "a")
26
+ )
27
+ @logger.level = Logger::DEBUG
28
+
29
+ setup_logger
30
+
31
+ # Setup slingshot
32
+ Slingshot::Configuration.url(self.url)
33
+ end
34
+
35
+ # Sets up the default settings of the logger
36
+ # @return [nil]
37
+ 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
+ }
42
+ end
43
+
44
+ # Returns the proper url for elasticsearch
45
+ # @return [String] url representation of the configuration options host and port
46
+ def url
47
+ "http://#{@host}:#{@port}"
48
+ end
49
+
50
+ private
51
+ # Creates tmp directory if it doesn't exist
52
+ # @return [nil]
53
+ def make_tmp_dir
54
+ FileUtils.mkdir_p @log_dir
55
+ Dir["#{@log_dir}/*"].each do |file|
56
+ FileUtils.rm_rf file
57
+ end
58
+ end
59
+
60
+ # Loads the configuration file
61
+ # @return [nil]
62
+ def parse_config
63
+ path = "#{Rails.root}/config/mebla.yml"
64
+ return unless File.exists?(path)
65
+
66
+ conf = YAML::load(ERB.new(IO.read(path)).result)[Rails.env]
67
+
68
+ conf.each do |key,value|
69
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
70
+ end unless conf.nil?
71
+ end
72
+ end
73
+ end