runes 0.1.1

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/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rubberband"
4
+
5
+ group :development do
6
+ gem "bundler", "~> 1.0.0"
7
+ gem "jeweler", "~> 1.5.2"
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ elasticsearch (0.0.0)
5
+ git (1.2.5)
6
+ jeweler (1.5.2)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.8.7)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ bundler (~> 1.0.0)
17
+ elasticsearch
18
+ jeweler (~> 1.5.2)
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2011, Stephano Zanzin
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ 3. Neither the name of the Stephano Zanzin nor the
12
+ names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY STEPHANO ZANZIN ''AS IS'' AND ANY
16
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL STEPHANO ZANZIN BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.markdown ADDED
@@ -0,0 +1,39 @@
1
+ Runes
2
+ ======
3
+
4
+ Runes is a Railtie to index your models using the modern Elasticsearch as backend, which have possibilities ranging from a simple single-node index manipulation to a highly populated cluster.
5
+
6
+ Elasticsearch
7
+ -------------
8
+
9
+ Elasticsearch is a powerful easy-to-use search engine built on top of Apache Lucene. It aims to solve many problems found when search is needed providing an amazing RESTful interface and complete ability to scale using a innovative distributed architecture. For more information check their [website](http://www.elasticsearch.org/).
10
+
11
+ Getting started
12
+ -------------
13
+
14
+ First of all, this plugin was designed using the new Railtie architecture, so it's only supported by Rails 3. If you are new to elasticsearch I encourage you to install it using their [installation guide](http://www.elasticsearch.org/guide/reference/setup/installation.html).
15
+
16
+ Install the latest gem in the conventional manner:
17
+
18
+ gem install runes
19
+
20
+ Specify the models you want to index:
21
+
22
+ class Cake < ActiveRecord::Base
23
+ acts_as_indexable
24
+ end
25
+
26
+ After you have installed Runes and specified the models just fire your Rails app. Voila! You are able to index and search.
27
+
28
+ Cake.create!(:name => "chocolate", :category => "fatty")
29
+ Cake.search("chocolate")
30
+
31
+ Author
32
+ ------
33
+
34
+ Stephano Zanzin :: me@zan.st :: zanst @ Freenode
35
+
36
+ NOTICE
37
+ ------
38
+
39
+ Work in progress, if you are not a code diver I recommend wait for a tag.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'psych' unless RUBY_VERSION < '1.9.2'
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the runes plugin.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.libs << 'test'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the runes plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'Runes'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ desc 'Build gem for the runes railtie.'
27
+ begin
28
+ require 'jeweler'
29
+ Jeweler::Tasks.new do |gem|
30
+ gem.name = 'runes'
31
+ gem.summary = 'Elasticsearch Railtie'
32
+ gem.description = 'Implements search to your models easily using elasticsearch as engine.'
33
+ gem.email = 'me@zan.st'
34
+ gem.homepage = 'http://github.com/zanst/runes'
35
+ gem.authors = ['Stephano Zanzin']
36
+ gem.files = Dir['*', '{lib}/**/*']
37
+ gem.add_dependency('rubberband')
38
+ end
39
+
40
+ Jeweler::GemcutterTasks.new
41
+ rescue LoadError
42
+ puts 'Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler'
43
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/lib/runes.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'rails'
2
+ require 'rubberband'
3
+
4
+ module Runes
5
+ require 'runes/base'
6
+ require 'runes/janitor'
7
+ require 'runes/orm/active_record'
8
+ require 'runes/railtie' if defined?(Rails)
9
+ require 'runes/rubberband_ext'
10
+
11
+ begin
12
+ config_path = Rails.root.to_s + '/config/runes.yml'
13
+ @config = YAML.load_file(config_path)
14
+ rescue
15
+ @config = nil
16
+ end
17
+
18
+ if Runes::Janitor.es_is_running?
19
+ @server_host = @config.nil? ? '127.0.0.1:9200' : @config['host'] + ':' + @config['port']
20
+ $es_client = ElasticSearch.new(@server_host)
21
+ end
22
+ end
data/lib/runes/base.rb ADDED
@@ -0,0 +1,18 @@
1
+ module Runes
2
+ module Base
3
+ class << self
4
+ def set_actor(model)
5
+ @actors ||= []
6
+ @actors << model
7
+ end
8
+
9
+ def actors
10
+ @actors
11
+ end
12
+
13
+ def search(query, index)
14
+ $es_client.search(query, :index => index)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ module Runes
2
+ module Janitor
3
+ class << self
4
+ def setup!
5
+ if Runes::Janitor.es_is_running?
6
+ begin
7
+ Runes::Base.actors.each do |actor|
8
+ $es_client.create_index(actor)
9
+ end
10
+ rescue ElasticSearch::RequestError
11
+ return true
12
+ end
13
+ end
14
+ end
15
+
16
+ # This function was created because rubberband
17
+ # behaves strangely and doesn't inform properly
18
+ # when elasticsearch isn't running.
19
+ def es_is_running?
20
+ require 'socket'
21
+ if @config.nil?
22
+ # getting the longer line possible to avoid problems in different operating systems.
23
+ process_status = system("ps auxwwww | grep org.elasticsearch.bootstrap | grep -v grep >> /dev/null")
24
+ return process_status
25
+ else
26
+ net_status = TCPSocket.open(@config['host'], @config['port'].to_i)
27
+ if net_status.nil?
28
+ return false
29
+ else
30
+ return true
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ module Runes
2
+ module Orm
3
+ module ActiveRecord
4
+ attr_accessor :index_name
5
+ attr_accessor :type_name
6
+
7
+ def acts_as_indexable(options={})
8
+ send :include, InstanceMethods
9
+ @index_name = self.name.underscore.gsub(/\//, '-').pluralize
10
+ @type_name = self.name.underscore.gsub(/\//, '-').singularize
11
+ Runes::Base.set_actor(@index_name)
12
+ after_destroy :destroy_object_from_index
13
+ after_save :add_object_to_index
14
+ end
15
+
16
+ def search(query)
17
+ search = Runes::Base.search(query, @index_name)
18
+ results = search.map{|result| result.ar_equivalence}
19
+ return results.sort_by(&:created_at)
20
+ end
21
+ end
22
+
23
+ module InstanceMethods
24
+ def destroy_object_from_index
25
+ $es_client.delete(self.id.to_s, :index => self.class.index_name, :type => self.class.type_name)
26
+ end
27
+
28
+ def add_object_to_index
29
+ begin
30
+ destroy_object_from_index
31
+ $es_client.index(self.to_json, :id => self.id, :index => self.class.index_name, :type => self.class.type_name)
32
+ rescue
33
+ $es_client.index(self.to_json, :id => self.id, :index => self.class.index_name, :type => self.class.type_name)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ require 'runes'
2
+ require 'rails'
3
+
4
+ module Runes
5
+ class Railtie < Rails::Railtie
6
+ # Check if elasticsearch is running.
7
+ initializer 'runes.check_es_status', :before => 'i18n.callbacks' do
8
+ if Runes::Janitor.es_is_running? == false
9
+ raise "Elasticsearch server is not running."
10
+ end
11
+ end
12
+
13
+ # Include module into Rubberband's ElasticSearch::Api::Hit
14
+ initializer 'runes.include.rubberband', :before => 'active_record.initialize_timezone' do
15
+ ElasticSearch::Api::Hit.send :include, Runes::RubberbandExtension
16
+ end
17
+
18
+ # Extends module into active_record.
19
+ initializer 'runes.extend.active_record', :after => 'runes.include.rubberband' do
20
+ ActiveRecord::Base.send :extend, Runes::Orm::ActiveRecord
21
+ end
22
+
23
+ # Initialize models in order to perform the Runes function.
24
+ initializer 'runes.req_models', :after => :engines_blank_point do
25
+ Dir.glob(Rails.root.to_s + '/app/models/*.rb').each { |file| require file }
26
+ end
27
+
28
+ # Verify and setup the actors defined by the user.
29
+ initializer 'runes.create_indexes', :after => 'runes.req_models' do
30
+ Runes::Janitor.setup!
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ module Runes
2
+ module RubberbandExtension
3
+ def ar_equivalence
4
+ model = _type.gsub(/-/,'/').classify.constantize
5
+ begin
6
+ model.find(id)
7
+ rescue ActiveRecord::RecordNotFound
8
+ nil
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ class RunesTest < ActiveSupport::TestCase
4
+ setup do
5
+ setup_db
6
+ ActiveRecord::Base.send :extend, Runes::Orm::ActiveRecord
7
+ end
8
+
9
+ must "execute method and add object to index" do
10
+ class Nut < ActiveRecord::Base
11
+ acts_as_indexable
12
+ end
13
+ Nut.create!(:name => "nutixious", :content => "nuts do crackle")
14
+ assert_equal 1, Nut.all.count
15
+ end
16
+
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support'
4
+ require 'active_record'
5
+ require 'test_unit_extension'
6
+
7
+ def setup_db
8
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
9
+
10
+ ActiveRecord::Schema.define(:version => 0) do
11
+ create_table :nuts, :force => true do |t|
12
+ t.string :name
13
+ t.text :content
14
+ t.datetime :created_at
15
+ end
16
+ end
17
+
18
+ require File.dirname(__FILE__) + '/../lib/runes'
19
+ end
20
+
21
+ ActiveSupport::TestCase.send :extend, Test::Unit
@@ -0,0 +1,21 @@
1
+ module Test::Unit
2
+ # Used to fix a minor minitest/unit incompatibility in flexmock
3
+ AssertionFailedError = Class.new(StandardError)
4
+
5
+ class TestCase
6
+
7
+ def self.must(name, &block)
8
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
9
+ defined = instance_method(test_name) rescue false
10
+ raise "#{test_name} is already defined in #{self}" if defined
11
+ if block_given?
12
+ define_method(test_name, &block)
13
+ else
14
+ define_method(test_name) do
15
+ flunk "No implementation provided for #{name}"
16
+ end
17
+ end
18
+ end
19
+
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: runes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stephano Zanzin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-05-15 00:00:00.000000000 -03:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rubberband
17
+ requirement: &7573140 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *7573140
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: &7564440 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *7564440
37
+ - !ruby/object:Gem::Dependency
38
+ name: jeweler
39
+ requirement: &7563100 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.5.2
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *7563100
48
+ - !ruby/object:Gem::Dependency
49
+ name: rubberband
50
+ requirement: &7561660 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *7561660
59
+ description: Implements search to your models easily using elasticsearch as engine.
60
+ email: me@zan.st
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - LICENSE
65
+ - README.markdown
66
+ files:
67
+ - Gemfile
68
+ - Gemfile.lock
69
+ - LICENSE
70
+ - README.markdown
71
+ - Rakefile
72
+ - VERSION
73
+ - lib/runes.rb
74
+ - lib/runes/base.rb
75
+ - lib/runes/janitor.rb
76
+ - lib/runes/orm/active_record.rb
77
+ - lib/runes/railtie.rb
78
+ - lib/runes/rubberband_extension.rb
79
+ - test/runes_test.rb
80
+ - test/test_helper.rb
81
+ - test/test_unit_extension.rb
82
+ has_rdoc: true
83
+ homepage: http://github.com/zanst/runes
84
+ licenses: []
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 1.6.2
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Elasticsearch Railtie
107
+ test_files:
108
+ - test/runes_test.rb
109
+ - test/test_helper.rb
110
+ - test/test_unit_extension.rb