elasticsearch-model-globalize 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e1ca50ca38311f893fa8b213704174c16a2facc3
4
+ data.tar.gz: 069ef0416c36d6bedc84b0702d8fe096bdd7524a
5
+ SHA512:
6
+ metadata.gz: f23d21df326bf57c9ef150e4e73f13a4703bf137f572441083f964ee7dc2f7ede3a30c3dce9af50289324b1343990fd078e9957b01cde0b683d1c0bc2dcde0d0
7
+ data.tar.gz: 31876715ab920f987f01847eb028dd592b44619a40df017daae1d520d07b378aa3011a1432918a2caca8d8aaa349ed2b917dc113bda89042e3a91a06f57341dc
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+
24
+ /vendor
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elasticsearch-model-globalize.gemspec
4
+ gemspec
5
+
6
+ gem 'pry-byebug', github: 'lencioni/pry-byebug', branch: '3.0.0'
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2014 Kentaro Imai
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # Elasticsearch::Model::Globalize
2
+
3
+ `elasticsearch-model-globalize` library allows you to use `elasticsearch-model` library
4
+ with `Globalize` gem.
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'elasticsearch-model-globalize'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install elasticsearch-model-globalize
20
+
21
+
22
+ ## Usage
23
+
24
+ There are a few ways to use `elasticsearch-model` with `Globalize`.
25
+
26
+ This gem has two modules, one is `MultipleFields` and the other is `OneIndexPerLanguage`.
27
+ You can choose one for each model to fit your needs by simply including a module.
28
+
29
+ ```ruby
30
+ class Item < ActiveRecord::Base
31
+ include Elasticsearch::Model
32
+ include Elasticsearch::Model::Callbacks
33
+ include Elasticsearch::Model::Globalize::MultipleFields
34
+ # Or
35
+ # include Elasticsearch::Model::Globalize::OneIndexPerLanguage
36
+ end
37
+ ```
38
+
39
+
40
+ ### MultipleFields
41
+
42
+ `MultipleFields` module creates additional fields for each language.
43
+ For example, you have a model like:
44
+
45
+ ```ruby
46
+ class Item < ActiveRecord::Base
47
+ translates :name, :description
48
+ include Elasticsearch::Model
49
+ include Elasticsearch::Model::Callbacks
50
+ include Elasticsearch::Model::Globalize::MultipleFields
51
+
52
+ mapping do
53
+ indexes :id, type: 'integer'
54
+ indexes :name_ja, analyzer: 'kuromoji'
55
+ indexes :name_en, analyzer: 'snowball'
56
+ indexes :description_ja, analyzer: 'kuromoji'
57
+ indexes :description_en, analyzer: 'snowball'
58
+ end
59
+ end
60
+ ```
61
+
62
+ and you have `:en` and `:ja` for available locales.
63
+
64
+ `MultipleFields` module creates `name_en`, `name_ja`, `description_en` and `description_ja`
65
+ field and stores these fields instead of `name` and `description` fields into Elasticsearch.
66
+
67
+ You can customize the way to localize field names.
68
+
69
+ ```ruby
70
+ # Put this in config/initializers/elasticsearch-model-globalize.rb
71
+ Elasticsearch::Model::Globalize::MultipleFields.localized_name do |name, locale|
72
+ "#{locale}_#{name}"
73
+ end
74
+ ```
75
+
76
+ One thing you have to care about is that put `translates` line before includeing
77
+ `Elasticsearch::Model::Globalize::MultipleFields`, otherwise `MultipleFields` module are not able to
78
+ know from which fields to derive localized fields.
79
+
80
+
81
+ ### OneIndexPerLanguage
82
+
83
+ `OneIndexPerLanguage` module creates one index per language.
84
+ For example, you have a model like:
85
+
86
+ ```ruby
87
+ class Item < ActiveRecord::Base
88
+ translates :name, :description
89
+ include Elasticsearch::Model
90
+ include Elasticsearch::Model::Callbacks
91
+ include Elasticsearch::Model::Globalize::OneIndexPerLanguage
92
+ end
93
+ ```
94
+
95
+ and you have `:en` and `:ja` for available locales,
96
+
97
+ `OneIndexPerLanguage` module creates `items-en` and `items-ja` indices.
98
+
99
+ You can customize the way to localize index names and document types.
100
+
101
+ ```ruby
102
+ # Put this in config/initializers/elasticsearch-model-globalize.rb
103
+ Elasticsearch::Model::Globalize::OneIndexPerLanguage.localized_name do |name, locale|
104
+ "#{locale}-#{name}"
105
+ end
106
+ ```
107
+
108
+ You can use `index_name_base` and `documenty_type_base` in addition to `index_name` and
109
+ `document_type`.
110
+
111
+
112
+ You can define mappings using `globalized_maping` as follows:
113
+
114
+ ```ruby
115
+ class Item < ActiveRecord::Base
116
+ translates :name, :description
117
+ include Elasticsearch::Model
118
+ include Elasticsearch::Model::Callbacks
119
+ include Elasticsearch::Model::OneIndexPerLanguage
120
+
121
+ globalized_mapping do |locale|
122
+ analyzer = locale == :ja ? 'kuromoji' : 'snowball'
123
+
124
+ indexes :id, type: 'integer'
125
+ indexes :name, analyzer: analyzer
126
+ indexes :description, analyzer: analyzer
127
+ end
128
+ end
129
+ ```
130
+
131
+
132
+ ## Development and Community
133
+
134
+ For local development, clone the repository and run bundle install.
135
+
136
+ To run all tests against a test Elasticsearch cluster, use a command like this:
137
+
138
+ ```sh
139
+ curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.2.1.tar.gz | tar xz -C tmp/
140
+ SERVER=start TEST_CLUSTER_COMMAND=$PWD/tmp/elasticsearch-1.2.1/bin/elasticsearch bundle exec rake test
141
+ ```
142
+
143
+
144
+ ## Contributing
145
+
146
+ 1. Fork it ( https://github.com/kentaroi/elasticsearch-model-globalize/fork )
147
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
148
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
149
+ 4. Push to the branch (`git push origin my-new-feature`)
150
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Goma'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elasticsearch/model/globalize/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "elasticsearch-model-globalize"
8
+ spec.version = Elasticsearch::Model::Globalize::VERSION
9
+ spec.authors = ["Kentaro Imai"]
10
+ spec.email = ["kentaroi@gmail.com"]
11
+ spec.summary = %q{A library for using elasticsearch-model with globalize}
12
+ spec.description = %q{A library for using elasticsearch-model with globalize}
13
+ spec.homepage = "https://github.com/kentaroi/elastic-search-model-globalize"
14
+ spec.license = "Apache 2"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'elasticsearch-model'
22
+ spec.add_dependency 'globalize'
23
+ spec.add_dependency 'activerecord'
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "sqlite3"
27
+ spec.add_development_dependency "minitest", "~> 4.0"
28
+ spec.add_development_dependency "shoulda-context"
29
+ spec.add_development_dependency "mocha"
30
+ spec.add_development_dependency "pry-alias"
31
+ spec.add_development_dependency "elasticsearch-extensions"
32
+ end
@@ -0,0 +1,10 @@
1
+ require "elasticsearch/model/globalize/version"
2
+
3
+ module Elasticsearch
4
+ module Model
5
+ module Globalize
6
+ autoload :MultipleFields, 'elasticsearch/model/globalize/multiple_fields'
7
+ autoload :OneIndexPerLanguage, 'elasticsearch/model/globalize/one_index_per_language'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,81 @@
1
+ module Elasticsearch
2
+ module Model
3
+ module Globalize
4
+ module MultipleFields
5
+ def self.included(base)
6
+ base.class_eval do
7
+ class << self
8
+ def locales
9
+ @locales ||= I18n.available_locales
10
+ end
11
+ end
12
+
13
+ locales.each do |locale|
14
+ translated_attribute_names.each do |name|
15
+ localized_name = MultipleFields.localized_name(name, locale)
16
+
17
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1 # Define getter
18
+ def #{localized_name}
19
+ globalize.stash.contains?(:#{locale}, '#{name}') ? globalize.stash[:#{locale}]['#{name}']
20
+ : translation_for(:#{locale}, false).try(:read_attribute, '#{name}')
21
+ end
22
+ METHOD
23
+
24
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1 # Define setter
25
+ def #{localized_name}=(val)
26
+ attribute_will_change!(:#{localized_name})
27
+ write_attribute('#{name}', val, locale: :#{locale})
28
+ end
29
+ METHOD
30
+ end
31
+ end
32
+
33
+ translated_attribute_names.each do |name|
34
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
35
+ def #{name}=(val)
36
+ attribute_will_change!(::Elasticsearch::Model::Globalize::MultipleFields.localized_name('#{name}', ::Globalize.locale))
37
+ write_attribute('#{name}', val)
38
+ end
39
+ METHOD
40
+ end
41
+
42
+ def __elasticsearch__ &block
43
+ unless @__elasticsearch__
44
+ @__elasticsearch__ = ::Elasticsearch::Model::Proxy::InstanceMethodsProxy.new(self)
45
+ @__elasticsearch__.extend Elasticsearch::Model::Globalize::MultipleFields::InstanceMethods
46
+ end
47
+ @__elasticsearch__.instance_eval(&block) if block_given?
48
+ @__elasticsearch__
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.localized_name(name=nil, locale=nil, &block)
54
+ @localizer = block if block_given?
55
+
56
+ @localizer ? @localizer.call(name, locale) : "#{name}_#{locale}"
57
+ end
58
+
59
+ module InstanceMethods
60
+ def as_globalized_json(options={})
61
+ h = self.as_json
62
+
63
+ translated_attribute_names.each do |name|
64
+ h.delete(name.to_s)
65
+
66
+ self.class.locales.each do |locale|
67
+ localized_name = Elasticsearch::Model::Globalize::MultipleFields.localized_name(name, locale)
68
+ h[localized_name] = send(localized_name)
69
+ end
70
+ end
71
+ h
72
+ end
73
+
74
+ def as_indexed_json(options={})
75
+ self.as_globalized_json(options.merge root: false)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,235 @@
1
+ module Elasticsearch
2
+ module Model
3
+ module Globalize
4
+ module OneIndexPerLanguage
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ self.__elasticsearch__.class_eval do
9
+ include Elasticsearch::Model::Globalize::OneIndexPerLanguage::ClassMethods
10
+ end
11
+
12
+ class << self
13
+ [:globalized_mapping, :globalized_mappings, :import_globally, :index_name_base, :index_name_base=, :document_type_base, :document_type_base=].each do |m|
14
+ delegate m, to: :__elasticsearch__
15
+ end
16
+ end
17
+
18
+ def __elasticsearch__ &block
19
+ unless @__elasticsearch__
20
+ @__elasticsearch__ = ::Elasticsearch::Model::Proxy::InstanceMethodsProxy.new(self)
21
+ @__elasticsearch__.extend Elasticsearch::Model::Globalize::OneIndexPerLanguage::InstanceMethods
22
+ end
23
+ @__elasticsearch__.instance_eval(&block) if block_given?
24
+ @__elasticsearch__
25
+ end
26
+
27
+ before_update :update_existence_of_documents
28
+ before_save :update_changed_attributes_by_locale
29
+ end
30
+ end
31
+
32
+ def self.localized_name(name=nil, locale=nil, &block)
33
+ @localizer = block if block_given?
34
+
35
+ @localizer ? @localizer.call(name, locale) : "#{name}-#{locale}"
36
+ end
37
+
38
+ module ClassMethods
39
+ def index_name_base name=nil
40
+ @index_name_base = name and index_names.clear if name
41
+ @index_name_base || self.model_name.collection.gsub(/\//, '-')
42
+ end
43
+
44
+ def index_name_base=(name)
45
+ index_names.clear
46
+ @index_name_base = name
47
+ end
48
+
49
+ def document_type_base name=nil
50
+ @document_type_base = name and document_types.clear if name
51
+ @document_type_base || self.model_name.element
52
+ end
53
+
54
+ def document_type_base=(name)
55
+ document_types.clear
56
+ @document_type_base = name
57
+ end
58
+
59
+ def index_name name=nil
60
+ @index_name = name if name
61
+ @index_name || index_names[::Globalize.locale] ||=
62
+ ::Elasticsearch::Model::Globalize::OneIndexPerLanguage.localized_name(index_name_base, ::Globalize.locale)
63
+ end
64
+
65
+ def index_names
66
+ @index_names ||= {}
67
+ end
68
+
69
+ def document_type name=nil
70
+ @document_type = name if name
71
+ @document_type || document_types[::Globalize.locale] ||=
72
+ ::Elasticsearch::Model::Globalize::OneIndexPerLanguage.localized_name(document_type_base, ::Globalize.locale)
73
+ end
74
+
75
+ def document_types
76
+ @document_types ||= {}
77
+ end
78
+
79
+ def globalized_mapping(options={}, &block)
80
+ unless @globalized_mapping
81
+ @globalized_mapping = ActiveSupport::HashWithIndifferentAccess.new
82
+ target.__elasticsearch__.class_eval <<-RUBY, __FILE__, __LINE__ + 1
83
+ def mapping
84
+ @globalized_mapping[::Globalize.locale]
85
+ end
86
+ alias :mappings :mapping
87
+ RUBY
88
+ end
89
+ I18n.available_locales.each do |locale|
90
+ @globalized_mapping[locale] ||= ::Elasticsearch::Model::Indexing::Mappings.new(
91
+ ::Elasticsearch::Model::Globalize::OneIndexPerLanguage.localized_name(document_type_base, locale), options)
92
+
93
+ if block_given?
94
+ @globalized_mapping[locale].options.update(options)
95
+
96
+ @globalized_mapping[locale].instance_exec(locale, &block)
97
+ end
98
+ end
99
+ @globalized_mapping
100
+ end
101
+ alias :globalized_mappings :globalized_mapping
102
+
103
+ def import(options={}, &block)
104
+ current_locale_only = options.delete(:current_locale_only)
105
+ if current_locale_only
106
+ super(options, &block)
107
+ else
108
+ errors = Hash.new
109
+ I18n.available_locales.each do |locale|
110
+ ::Globalize.with_locale(locale) do
111
+ errors[locale] = super(options, &block)
112
+ end
113
+ end
114
+ self.find_each do |record|
115
+ (I18n.available_locales - record.translations.pluck(:locale).map(&:to_sym)).each do |locale|
116
+ ::Globalize.with_locale(locale) do
117
+ record.__elasticsearch__.delete_document(current_locale_only: true)
118
+ end
119
+ end
120
+ end
121
+ errors
122
+ end
123
+ end
124
+ end
125
+
126
+ module InstanceMethods
127
+ attr_accessor :existence_of_documents, :changed_attributes_by_locale
128
+
129
+ def changed_attributes_by_locale
130
+ @changed_attributes_by_locale ||= ActiveSupport::HashWithIndifferentAccess.new
131
+ end
132
+
133
+ def existence_of_documents
134
+ @existence_of_documents ||= ActiveSupport::HashWithIndifferentAccess.new
135
+ end
136
+
137
+ def index_name_base name=nil
138
+ @index_name_base = name || @index_name_base || self.class.index_name_base
139
+ end
140
+
141
+ def index_name_base=(name)
142
+ @index_name_base = name
143
+ end
144
+
145
+ def document_type_base name=nil
146
+ @document_type_base = name || @document_type_base || self.class.document_type_base
147
+ end
148
+
149
+ def document_type_base=(name)
150
+ @document_type_base = name
151
+ end
152
+
153
+ def index_name
154
+ self.class.index_name
155
+ end
156
+
157
+ def document_type
158
+ self.class.document_type
159
+ end
160
+
161
+ def index_document(options={})
162
+ current_locale_only = options.delete(:current_locale_only)
163
+ if current_locale_only
164
+ super(options)
165
+ else
166
+ changed_attributes_by_locale.keys.each do |locale|
167
+ ::Globalize.with_locale(locale) do
168
+ super(options)
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ def update_document(options={})
175
+ changed_attributes_by_locale.keys.each do |locale|
176
+ ::Globalize.with_locale(locale) do
177
+ if existence_of_documents[locale]
178
+ attributes = if respond_to?(:as_indexed_json)
179
+ changed_attributes_by_locale[locale].select{ |k, v| as_indexed_json.keys.include? k }
180
+ else
181
+ changed_attributes_by_locale[locale]
182
+ end
183
+
184
+ client.update(
185
+ { index: index_name,
186
+ type: document_type,
187
+ id: self.id,
188
+ body: { doc: attributes } }.merge(options)
189
+ )
190
+ else
191
+ index_document(current_locale_only: true)
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ def delete_document(options={})
198
+ current_locale_only = options.delete(:current_locale_only)
199
+ if current_locale_only
200
+ super(options)
201
+ else
202
+ translations.pluck(:locale).each do |locale|
203
+ ::Globalize.with_locale(locale) do
204
+ super(options)
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ # This method actually checks existence of translations in database
212
+ # Therefore, database and elasticsearch must be synced.
213
+ def update_existence_of_documents
214
+ __elasticsearch__.existence_of_documents.clear
215
+ translations.each do |t|
216
+ __elasticsearch__.existence_of_documents[t.locale] = true if t.persisted?
217
+ end
218
+ true
219
+ end
220
+
221
+ def update_changed_attributes_by_locale
222
+ __elasticsearch__.changed_attributes_by_locale.clear
223
+
224
+ common_changed_attributes = Hash[ changes.map{ |key, value| [key, value.last] } ]
225
+ translated_attribute_names.each { |k| common_changed_attributes.delete(k) }
226
+
227
+ globalize.stash.reject{ |locale, attrs| attrs.empty? }.each do |locale, attrs|
228
+ __elasticsearch__.changed_attributes_by_locale[locale] = attrs.merge(common_changed_attributes)
229
+ end
230
+ true
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,7 @@
1
+ module Elasticsearch
2
+ module Model
3
+ module Globalize
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ require 'test_helper'
2
+ require 'elasticsearch/model/globalize/multiple_fields'
3
+
4
+ class MultipleFieldsIntegrationTest < Elasticsearch::Test::IntegrationTestCase
5
+
6
+ class Article < ActiveRecord::Base
7
+ translates :title
8
+ @locales = [:en, :ja]
9
+ include Elasticsearch::Model
10
+ include Elasticsearch::Model::Callbacks
11
+ include Elasticsearch::Model::Globalize::MultipleFields
12
+
13
+ settings index: {number_of_shards: 1, number_of_replicas: 1} do
14
+ mapping do
15
+ indexes :title_en, analyzer: 'snowball'
16
+ indexes :title_ja, analyzer: 'cjk'
17
+ end
18
+ end
19
+ end
20
+
21
+ context "Mulfield module" do
22
+ setup do
23
+ ActiveRecord::Schema.define(version: 1) do
24
+ create_table :articles do |t|
25
+ t.string :title
26
+ end
27
+ Article.create_translation_table! title: :string
28
+ end
29
+ Article.destroy_all
30
+ Article.__elasticsearch__.create_index! force: true
31
+ a = Article.new
32
+ a.title = 'Search engine'
33
+ Globalize.with_locale(:ja) { a.title = '検索エンジン' }
34
+ a.save!
35
+ Globalize.with_locale(:ja) { Article.create! title: '世界貿易機関 World Trade Organization' }
36
+ Article.create! title: 'Testing code'
37
+ Article.__elasticsearch__.refresh_index!
38
+ end
39
+
40
+ should 'search' do
41
+ assert_equal 1, Article.search('search').results.total
42
+ assert_equal 1, Article.search('検索').results.total
43
+ end
44
+
45
+ should 'mapping' do
46
+ assert_equal 1, Article.search('title_en:testing').results.total
47
+ assert_equal 1, Article.search('title_en:test').results.total, 'Should be snowball analyzer'
48
+ assert_equal 1, Article.search('title_ja:organization').results.total
49
+ assert_equal 0, Article.search('title_ja:organ').results.total, 'Should not be snowball analyzer'
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+ require 'elasticsearch/model/globalize/one_index_per_language'
3
+
4
+ class OneIndexPerLanguageIntegrationTest < Elasticsearch::Test::IntegrationTestCase
5
+
6
+ class Article < ActiveRecord::Base
7
+ translates :title
8
+ include Elasticsearch::Model
9
+ include Elasticsearch::Model::Callbacks
10
+ include Elasticsearch::Model::Globalize::OneIndexPerLanguage
11
+
12
+ settings index: {number_of_shards: 1, number_of_replicas: 1} do
13
+ globalized_mapping do |locale|
14
+ if locale == :en
15
+ indexes :title, analyzer: 'snowball'
16
+ else
17
+ indexes :title, analyzer: 'cjk'
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ context "OneIndexPerLanguage module" do
24
+ setup do
25
+ ActiveRecord::Schema.define(version: 1) do
26
+ create_table :articles do |t|
27
+ t.string :title
28
+ end
29
+ Article.create_translation_table! title: :string
30
+ end
31
+ Article.destroy_all
32
+ Article.__elasticsearch__.create_index! force: true
33
+ a = Article.new
34
+ a.title = 'Search engine'
35
+ Globalize.with_locale(:ja) { a.title = '検索エンジン' }
36
+ a.save!
37
+ Globalize.with_locale(:ja) { Article.create! title: '世界貿易機関 World Trade Organization' }
38
+ Article.create! title: 'Testing code'
39
+ Article.__elasticsearch__.refresh_index!
40
+ sleep 1
41
+ end
42
+
43
+ should 'search' do
44
+ Globalize.with_locale(:en) do
45
+ assert_equal 1, Article.search('search').results.total
46
+ assert_equal 0, Article.search('検索').results.total
47
+ end
48
+
49
+ Globalize.with_locale(:ja) do
50
+ assert_equal 0, Article.search('search').results.total
51
+ assert_equal 1, Article.search('検索').results.total
52
+ end
53
+ end
54
+
55
+ should 'mapping' do
56
+ Globalize.with_locale(:en) do
57
+ assert_equal 1, Article.search('title:testing').results.total
58
+ assert_equal 1, Article.search('title:test').results.total, 'Should be snowball analyzer'
59
+ end
60
+
61
+ Globalize.with_locale(:ja) do
62
+ assert_equal 1, Article.search('title:organization').results.total
63
+ assert_equal 0, Article.search('title:organ').results.total, 'Should not be snowball analyzer'
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,56 @@
1
+ RUBY_1_8 = defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
2
+
3
+ exit(0) if RUBY_1_8
4
+
5
+ # Register `at_exit` handler for integration tests shutdown
6
+ # MUST be called before requiring 'test/unit'
7
+ if defined?(RUBY_VERSION) && RUBY_VERSION > '1.9'
8
+ at_exit { Elasticsearch::Test::IntegrationTestCase.__run_at_exit_hooks }
9
+ end
10
+
11
+ require 'test/unit'
12
+ require 'shoulda-context'
13
+ require 'mocha/setup'
14
+ require 'pry-byebug'
15
+ require 'pry-alias'
16
+
17
+ require 'active_record'
18
+ require 'active_model'
19
+
20
+ require 'elasticsearch/model'
21
+
22
+ require 'elasticsearch/extensions/test/cluster'
23
+ require 'elasticsearch/extensions/test/startup_shutdown'
24
+
25
+ require 'globalize'
26
+
27
+
28
+ module Elasticsearch
29
+ module Test
30
+ class IntegrationTestCase < ::Test::Unit::TestCase
31
+ extend Elasticsearch::Extensions::Test::StartupShutdown
32
+
33
+ startup { Elasticsearch::Extensions::Test::Cluster.start(nodes: 1) if ENV['SERVER'] and not Elasticsearch::Extensions::Test::Cluster.running? }
34
+ shutdown { Elasticsearch::Extensions::Test::Cluster.stop if ENV['SERVER'] && started? }
35
+
36
+ def setup
37
+ ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ":memory:" )
38
+ logger = ::Logger.new(STDERR)
39
+ logger.formatter = lambda { |s, d, p, m| "#{m.ansi(:faint, :cyan)}\n" }
40
+ ActiveRecord::Base.logger = logger unless ENV['QUIET']
41
+
42
+ ActiveRecord::LogSubscriber.colorize_logging = false
43
+ ActiveRecord::Migration.verbose = false
44
+
45
+ tracer = ::Logger.new(STDERR)
46
+ tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
47
+
48
+ Elasticsearch::Model.client = Elasticsearch::Client.new host: "localhost:#{(ENV['TEST_CLUSTER_PORT'] || 9250)}",
49
+ tracer: (ENV['QUIET'] ? nil : tracer)
50
+
51
+ I18n.enforce_available_locales = true
52
+ I18n.available_locales = [:en, :ja]
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,126 @@
1
+ require 'test_helper'
2
+ require 'elasticsearch/model/globalize/multiple_fields'
3
+
4
+ class MultipleFieldsTest < Test::Unit::TestCase
5
+ class Article < ActiveRecord::Base
6
+ translates :title, :body
7
+ @locales = [:en, :ja]
8
+ include Elasticsearch::Model
9
+ include Elasticsearch::Model::Callbacks
10
+ include Elasticsearch::Model::Globalize::MultipleFields
11
+ end
12
+
13
+ def setup
14
+ ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ":memory:" )
15
+ logger = ::Logger.new(STDERR)
16
+ logger.formatter = lambda { |s, d, p, m| "#{m.ansi(:faint, :cyan)}\n" }
17
+ ActiveRecord::Base.logger = logger unless ENV['QUIET']
18
+
19
+ ActiveRecord::LogSubscriber.colorize_logging = false
20
+ ActiveRecord::Migration.verbose = false
21
+
22
+ tracer = ::Logger.new(STDERR)
23
+ tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
24
+
25
+
26
+ ActiveRecord::Schema.define(version: 1) do
27
+ create_table :articles do |t|
28
+ t.string :title
29
+ t.text :body
30
+ t.string :code
31
+ end
32
+ Article.create_translation_table! title: :string, body: :text
33
+ end
34
+ I18n.enforce_available_locales = true
35
+ I18n.available_locales = [:en, :ja]
36
+ end
37
+
38
+ def test_multiple_fields_attribute
39
+ a = Article.new
40
+ assert_nil a.title
41
+ a.title = 'English'
42
+ assert_equal 'English', a.title
43
+ assert_equal 'English', a.title_en
44
+ assert_nil a.title_ja
45
+ assert_equal 2, a.changes.keys.count
46
+ assert a.changes.has_key?(:title_en)
47
+ assert a.changes.has_key?(:title)
48
+
49
+ Globalize.with_locale(:ja) {
50
+ assert_nil a.title
51
+ a.title = '日本語'
52
+ assert_equal '日本語', a.title
53
+ assert_equal '日本語', a.title_ja
54
+ assert_equal 'English', a.title_en
55
+ assert_equal 3, a.changes.keys.count
56
+ assert a.changes.has_key?(:title_en)
57
+ assert a.changes.has_key?(:title_ja)
58
+ assert a.changes.has_key?(:title)
59
+ }
60
+ assert_equal 'English', a.title
61
+ assert_equal 'English', a.title_en
62
+ assert_equal '日本語', a.title_ja
63
+
64
+ a.title_en = 'English title'
65
+ assert_equal 'English title', a.title_en
66
+ a.title_ja = '日本語タイトル'
67
+ assert_equal '日本語タイトル', a.title_ja
68
+ assert_equal 'English title', a.title
69
+ assert_equal '日本語タイトル', Globalize.with_locale(:ja){ a.title }
70
+ end
71
+
72
+ def test_create
73
+ a = Article.new
74
+ a.title = 'title'
75
+ assert_equal 'title', a.title_en
76
+ a.__elasticsearch__.client.expects(:index).with { |value|
77
+ value[:index] == 'multiple_fields_test-articles' &&
78
+ value[:type] == 'article' &&
79
+ value[:body].count == 6 &&
80
+ value[:body].has_key?('id') &&
81
+ value[:body]['title_en'] == 'title' &&
82
+ value[:body]['title_ja'] == nil &&
83
+ value[:body]['body_en'] == nil &&
84
+ value[:body]['body_ja'] == nil &&
85
+ value[:body]['code'] == nil
86
+ }
87
+ a.save
88
+ end
89
+
90
+ def test_update
91
+ a = Article.new
92
+ a.__elasticsearch__.stubs(:index_document)
93
+ a.title = 'title'
94
+ a.body = 'body'
95
+ a.save
96
+ a.title = 'new title'
97
+ a.__elasticsearch__.client.expects(:update).with { |value|
98
+ value[:index] == 'multiple_fields_test-articles' &&
99
+ value[:type] == 'article' &&
100
+ value[:id] == a.id &&
101
+ value[:body][:doc].count == 1 &&
102
+ value[:body][:doc]['title_en'] == 'new title'
103
+ }
104
+ a.save
105
+ end
106
+
107
+ def test_update_with_no_translation_field
108
+ a = Article.new
109
+ a.__elasticsearch__.stubs(:index_document)
110
+ a.title = 'title'
111
+ a.body = 'body'
112
+ a.code = 'code'
113
+ a.save
114
+ a.title = 'new title'
115
+ a.code = 'no derived fields'
116
+ a.__elasticsearch__.client.expects(:update).with { |value|
117
+ value[:index] == 'multiple_fields_test-articles' &&
118
+ value[:type] == 'article' &&
119
+ value[:id] == a.id &&
120
+ value[:body][:doc].count == 2 &&
121
+ value[:body][:doc]['title_en'] == 'new title'
122
+ value[:body][:doc]['code'] == 'no derived fields'
123
+ }
124
+ a.save
125
+ end
126
+ end
@@ -0,0 +1,137 @@
1
+ require 'test_helper'
2
+ require 'elasticsearch/model/globalize/one_index_per_language'
3
+
4
+ class OneIndexPerLanguageTest < Test::Unit::TestCase
5
+ class Article < ActiveRecord::Base
6
+ translates :title, :body
7
+ @locales = [:en, :ja]
8
+ include Elasticsearch::Model
9
+ include Elasticsearch::Model::Callbacks
10
+ include Elasticsearch::Model::Globalize::OneIndexPerLanguage
11
+ end
12
+
13
+ def setup
14
+ ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ":memory:" )
15
+ logger = ::Logger.new(STDERR)
16
+ logger.formatter = lambda { |s, d, p, m| "#{m.ansi(:faint, :cyan)}\n" }
17
+ ActiveRecord::Base.logger = logger unless ENV['QUIET']
18
+
19
+ ActiveRecord::LogSubscriber.colorize_logging = false
20
+ ActiveRecord::Migration.verbose = false
21
+
22
+ tracer = ::Logger.new(STDERR)
23
+ tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
24
+
25
+
26
+ ActiveRecord::Schema.define(version: 1) do
27
+ create_table :articles do |t|
28
+ t.string :title
29
+ t.text :body
30
+ t.string :code
31
+ end
32
+ Article.create_translation_table! title: :string, body: :text
33
+ end
34
+ I18n.enforce_available_locales = true
35
+ I18n.available_locales = [:en, :ja]
36
+ end
37
+
38
+ def test_create
39
+ a = Article.new
40
+ a.title = 'title'
41
+ a.__elasticsearch__.client.expects(:index).with { |value|
42
+ value[:index] == 'one_index_per_language_test-articles-en' &&
43
+ value[:type] == 'article-en' &&
44
+ value[:body].count == 4 &&
45
+ value[:body].has_key?('id') &&
46
+ value[:body]['title'] == 'title' &&
47
+ value[:body]['body'] == nil &&
48
+ value[:body]['code'] == nil
49
+ }
50
+ a.save
51
+ end
52
+
53
+ def test_create_multiple_locales
54
+ a = Article.new
55
+ a.title = 'title'
56
+ Globalize.with_locale(:ja) { a.title = 'タイトル' }
57
+ a.__elasticsearch__.client.expects(:index).with { |value|
58
+ value[:index] == 'one_index_per_language_test-articles-en' &&
59
+ value[:type] == 'article-en' &&
60
+ value[:body].count == 4 &&
61
+ value[:body].has_key?('id') &&
62
+ value[:body]['title'] == 'title' &&
63
+ value[:body]['body'] == nil &&
64
+ value[:body]['code'] == nil
65
+ }
66
+ a.__elasticsearch__.client.expects(:index).with { |value|
67
+ value[:index] == 'one_index_per_language_test-articles-ja' &&
68
+ value[:type] == 'article-ja' &&
69
+ value[:body].count == 4 &&
70
+ value[:body].has_key?('id') &&
71
+ value[:body]['title'] == 'タイトル' &&
72
+ value[:body]['body'] == nil &&
73
+ value[:body]['code'] == nil
74
+ }
75
+ a.save
76
+ end
77
+
78
+ def test_create_with_no_translation_field
79
+ a = Article.new
80
+ a.title = 'title'
81
+ a.code = 'code'
82
+ a.__elasticsearch__.client.expects(:index).with { |value|
83
+ value[:index] == 'one_index_per_language_test-articles-en' &&
84
+ value[:type] == 'article-en' &&
85
+ value[:body].count == 4 &&
86
+ value[:body].has_key?('id') &&
87
+ value[:body]['title'] == 'title' &&
88
+ value[:body]['body'] == nil &&
89
+ value[:body]['code'] == 'code'
90
+ }
91
+ a.save
92
+ end
93
+
94
+ def test_update
95
+ a = Article.new
96
+ a.__elasticsearch__.stubs(:index_document)
97
+ a.title = 'title'
98
+ a.body = 'body'
99
+ a.save
100
+ a.title = 'new title'
101
+ a.__elasticsearch__.client.expects(:update).with { |value|
102
+ value[:index] == 'one_index_per_language_test-articles-en' &&
103
+ value[:type] == 'article-en' &&
104
+ value[:id] == a.id &&
105
+ value[:body][:doc].count == 1 &&
106
+ value[:body][:doc]['title'] == 'new title'
107
+ }
108
+ a.save
109
+ end
110
+
111
+ def test_update_with_new_locale
112
+ a = Article.new
113
+ a.__elasticsearch__.client.stubs(:index)
114
+ a.title = 'title'
115
+ a.body = 'body'
116
+ a.save
117
+ a.title = 'new title'
118
+ Globalize.with_locale(:ja) { a.title = 'タイトル' }
119
+ a.__elasticsearch__.client.expects(:update).with { |value|
120
+ value[:index] == 'one_index_per_language_test-articles-en' &&
121
+ value[:type] == 'article-en' &&
122
+ value[:id] == a.id &&
123
+ value[:body][:doc].count == 1 &&
124
+ value[:body][:doc]['title'] == 'new title'
125
+ }
126
+ a.__elasticsearch__.client.expects(:index).with { |value|
127
+ value[:index] == 'one_index_per_language_test-articles-ja' &&
128
+ value[:type] == 'article-ja' &&
129
+ value[:body].count == 4 &&
130
+ value[:body].has_key?('id') &&
131
+ value[:body]['title'] == 'タイトル' &&
132
+ value[:body]['body'] == nil &&
133
+ value[:body]['code'] == nil
134
+ }
135
+ a.save
136
+ end
137
+ end
metadata ADDED
@@ -0,0 +1,218 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elasticsearch-model-globalize
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kentaro Imai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: elasticsearch-model
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: globalize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: shoulda-context
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: mocha
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry-alias
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: elasticsearch-extensions
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: A library for using elasticsearch-model with globalize
168
+ email:
169
+ - kentaroi@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".gitignore"
175
+ - Gemfile
176
+ - LICENSE.txt
177
+ - README.md
178
+ - Rakefile
179
+ - elasticsearch-model-globalize.gemspec
180
+ - lib/elasticsearch/model/globalize.rb
181
+ - lib/elasticsearch/model/globalize/multiple_fields.rb
182
+ - lib/elasticsearch/model/globalize/one_index_per_language.rb
183
+ - lib/elasticsearch/model/globalize/version.rb
184
+ - test/integration/multiple_fields_integration_test.rb
185
+ - test/integration/one_index_per_language_integration_test.rb
186
+ - test/test_helper.rb
187
+ - test/unit/multiple_fields_test.rb
188
+ - test/unit/one_index_per_language_test.rb
189
+ homepage: https://github.com/kentaroi/elastic-search-model-globalize
190
+ licenses:
191
+ - Apache 2
192
+ metadata: {}
193
+ post_install_message:
194
+ rdoc_options: []
195
+ require_paths:
196
+ - lib
197
+ required_ruby_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ required_rubygems_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ requirements: []
208
+ rubyforge_project:
209
+ rubygems_version: 2.2.2
210
+ signing_key:
211
+ specification_version: 4
212
+ summary: A library for using elasticsearch-model with globalize
213
+ test_files:
214
+ - test/integration/multiple_fields_integration_test.rb
215
+ - test/integration/one_index_per_language_integration_test.rb
216
+ - test/test_helper.rb
217
+ - test/unit/multiple_fields_test.rb
218
+ - test/unit/one_index_per_language_test.rb