supple 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "4.1.0.beta2"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,145 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ supple (0.1.0)
5
+ ansi
6
+ bonfig
7
+ connection_pool
8
+ elasticsearch
9
+ patron
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ actionmailer (4.1.0.beta2)
15
+ actionpack (= 4.1.0.beta2)
16
+ actionview (= 4.1.0.beta2)
17
+ mail (~> 2.5.4)
18
+ actionpack (4.1.0.beta2)
19
+ actionview (= 4.1.0.beta2)
20
+ activesupport (= 4.1.0.beta2)
21
+ rack (~> 1.5.2)
22
+ rack-test (~> 0.6.2)
23
+ actionview (4.1.0.beta2)
24
+ activesupport (= 4.1.0.beta2)
25
+ builder (~> 3.1)
26
+ erubis (~> 2.7.0)
27
+ activemodel (4.1.0.beta2)
28
+ activesupport (= 4.1.0.beta2)
29
+ builder (~> 3.1)
30
+ activerecord (4.1.0.beta2)
31
+ activemodel (= 4.1.0.beta2)
32
+ activesupport (= 4.1.0.beta2)
33
+ arel (~> 5.0.0)
34
+ activesupport (4.1.0.beta2)
35
+ i18n (~> 0.6, >= 0.6.9)
36
+ json (~> 1.7, >= 1.7.7)
37
+ minitest (~> 5.1)
38
+ thread_safe (~> 0.1)
39
+ tzinfo (~> 1.1)
40
+ ansi (1.4.3)
41
+ appraisal (0.5.2)
42
+ bundler
43
+ rake
44
+ arel (5.0.0)
45
+ atomic (1.1.15)
46
+ bonfig (0.1.1)
47
+ builder (3.2.2)
48
+ coderay (1.1.0)
49
+ connection_pool (1.2.0)
50
+ diff-lcs (1.2.5)
51
+ elasticsearch (1.0.1)
52
+ elasticsearch-api (= 1.0.1)
53
+ elasticsearch-transport (= 1.0.1)
54
+ elasticsearch-api (1.0.1)
55
+ multi_json
56
+ elasticsearch-transport (1.0.1)
57
+ faraday
58
+ multi_json
59
+ erubis (2.7.0)
60
+ factory_girl (4.4.0)
61
+ activesupport (>= 3.0.0)
62
+ faraday (0.9.0)
63
+ multipart-post (>= 1.2, < 3)
64
+ hike (1.2.3)
65
+ i18n (0.6.9)
66
+ json (1.8.1)
67
+ mail (2.5.4)
68
+ mime-types (~> 1.16)
69
+ treetop (~> 1.4.8)
70
+ method_source (0.8.2)
71
+ mime-types (1.25.1)
72
+ minitest (5.3.0)
73
+ multi_json (1.9.0)
74
+ multipart-post (2.0.0)
75
+ patron (0.4.18)
76
+ polyglot (0.3.4)
77
+ pry (0.9.12.6)
78
+ coderay (~> 1.0)
79
+ method_source (~> 0.8)
80
+ slop (~> 3.4)
81
+ rack (1.5.2)
82
+ rack-test (0.6.2)
83
+ rack (>= 1.0)
84
+ rails (4.1.0.beta2)
85
+ actionmailer (= 4.1.0.beta2)
86
+ actionpack (= 4.1.0.beta2)
87
+ actionview (= 4.1.0.beta2)
88
+ activemodel (= 4.1.0.beta2)
89
+ activerecord (= 4.1.0.beta2)
90
+ activesupport (= 4.1.0.beta2)
91
+ bundler (>= 1.3.0, < 2.0)
92
+ railties (= 4.1.0.beta2)
93
+ sprockets-rails (~> 2.0.0)
94
+ railties (4.1.0.beta2)
95
+ actionpack (= 4.1.0.beta2)
96
+ activesupport (= 4.1.0.beta2)
97
+ rake (>= 0.8.7)
98
+ thor (>= 0.18.1, < 2.0)
99
+ rake (0.9.6)
100
+ rspec (2.14.1)
101
+ rspec-core (~> 2.14.0)
102
+ rspec-expectations (~> 2.14.0)
103
+ rspec-mocks (~> 2.14.0)
104
+ rspec-core (2.14.8)
105
+ rspec-expectations (2.14.5)
106
+ diff-lcs (>= 1.1.3, < 2.0)
107
+ rspec-mocks (2.14.6)
108
+ rubygems-tasks (0.2.4)
109
+ slop (3.4.7)
110
+ sprockets (2.11.0)
111
+ hike (~> 1.2)
112
+ multi_json (~> 1.0)
113
+ rack (~> 1.0)
114
+ tilt (~> 1.1, != 1.3.0)
115
+ sprockets-rails (2.0.1)
116
+ actionpack (>= 3.0)
117
+ activesupport (>= 3.0)
118
+ sprockets (~> 2.8)
119
+ sqlite3 (1.3.9)
120
+ thor (0.18.1)
121
+ thread_safe (0.2.0)
122
+ atomic (>= 1.1.7, < 2)
123
+ tilt (1.4.1)
124
+ treetop (1.4.15)
125
+ polyglot
126
+ polyglot (>= 0.3.1)
127
+ tzinfo (1.1.0)
128
+ thread_safe (~> 0.1)
129
+ yard (0.8.7.3)
130
+
131
+ PLATFORMS
132
+ ruby
133
+
134
+ DEPENDENCIES
135
+ appraisal
136
+ bundler
137
+ factory_girl
138
+ pry
139
+ rails (= 4.1.0.beta2)
140
+ rake
141
+ rspec
142
+ rubygems-tasks
143
+ sqlite3
144
+ supple!
145
+ yard
@@ -0,0 +1,38 @@
1
+ require 'elasticsearch'
2
+ require 'connection_pool'
3
+ require 'active_support/core_ext'
4
+ require 'bonfig'
5
+ require 'rails'
6
+
7
+
8
+
9
+ module Supple
10
+ extend Bonfig
11
+
12
+ bonfig do
13
+ config :index_name_method, default: Proc.new { |model| [model.table_name, Rails.env].join('_') }
14
+ config :index do
15
+ config :default_index_name, default: Proc.new { |model| [model.table_name, Rails.env].join('_') }
16
+ config :default_document_type, default: Proc.new { |model| model.table_name }
17
+ end
18
+ config :client do
19
+ config :size, default: 5
20
+ config :timeout, default: 1
21
+ end
22
+ end
23
+
24
+ def self.models
25
+ ActiveRecord::Base.descendants.select do |m|
26
+ m.included_modules.include?(Supple::Model)
27
+ end
28
+ end
29
+
30
+ def self.client
31
+ @client ||= Elasticsearch::Client.new(adapter: :patron)
32
+ end
33
+ end
34
+ require 'supple/defaults'
35
+ require 'supple/model/dsl'
36
+ require 'supple/model'
37
+ # require 'supple/index'
38
+ require 'supple/railtie' if defined?(Rails)
@@ -0,0 +1,30 @@
1
+ module Supple
2
+ SETTINGS = {
3
+ number_of_shards: 1,
4
+ number_of_replicas: 0,
5
+ analysis: {
6
+ analyzer: {
7
+ word_start_ngram: {
8
+ type: "custom",
9
+ tokenizer: "word_start_ngram_tokenizer",
10
+ filter: ["lowercase", "asciifolding"]
11
+ },
12
+ words: {
13
+ type: "custom",
14
+ tokenizer: "keyword",
15
+ filter: ["lowercase", "asciifolding"]
16
+ }
17
+ },
18
+ tokenizer: {
19
+ word_start_ngram_tokenizer: {
20
+ type: "edgeNGram",
21
+ min_gram: 1,
22
+ max_gram: 50,
23
+ token_chars: ["letter"]
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+
30
+ end
@@ -0,0 +1,31 @@
1
+ module Supple
2
+ class IndexConfig < BasicObject
3
+ end
4
+ class Index
5
+ include ActiveSupport::DescendantsTracker
6
+
7
+ def self.settings(data = nil)
8
+ @settings = data unless data.nil?
9
+ @settings
10
+ end
11
+
12
+ def self.mappings(data = nil)
13
+ @mappings = data unless data.nil?
14
+ @mappings
15
+ end
16
+
17
+
18
+ with_options instance_writer: false do
19
+ cattr_accessor :model do
20
+ binding.pry
21
+ end
22
+ cattr_accessor :index_name do
23
+ [table_name, Rails.env].join('_')
24
+ end
25
+
26
+ cattr_accessor :document_type do
27
+ table_name
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,152 @@
1
+ module Supple
2
+ module WithClient
3
+ extend ActiveSupport::Concern
4
+ mattr_reader :client do
5
+ Supple.client
6
+ end
7
+ end
8
+
9
+ class Importer
10
+ def initialize(scope, index_name, document_type)
11
+ @scope = scope
12
+ @index_name = index_name
13
+ @document_type = document_type
14
+ end
15
+
16
+ def execute!
17
+ @scope.find_in_batches do |batch|
18
+ Supple.client.bulk({
19
+ index: @index_name,
20
+ type: @document_type,
21
+ body: transform_batch(batch)
22
+ })
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ def transform_batch(batch)
29
+ batch.map { |a| { index: { _id: a.id, data: a.as_indexed_json } } }
30
+ end
31
+ end
32
+
33
+
34
+ class ModelClient
35
+ attr_reader :model
36
+ delegate :index_name, :document_type, :as_indexed_json, to: :model
37
+
38
+ def initialize(model)
39
+ @model = model
40
+ end
41
+
42
+ def index
43
+ run(:index, body: as_indexed_json)
44
+ end
45
+
46
+ def delete
47
+ run(:delete)
48
+ end
49
+
50
+ private
51
+
52
+ def run(method, extra = {})
53
+ action = Supple.client.method(method)
54
+ action.call({
55
+ index: index_name,
56
+ type: document_type,
57
+ id: model.id,
58
+ }).merge(extra)
59
+ end
60
+ end
61
+
62
+
63
+ class Config
64
+ def client
65
+ Supple.client
66
+ end
67
+ def initialize(model)
68
+ @model = model
69
+
70
+ @index_name_method = Supple.config.index.default_index_name
71
+ @document_type_method = Supple.config.index.default_document_type
72
+ end
73
+
74
+ def index_name(&block)
75
+ @index_name_method = block if block_given?
76
+ @index_name ||= @index_name_method.call(@model)
77
+ end
78
+
79
+ def document_type(&block)
80
+ @document_type_method = block if block_given?
81
+ @document_type ||= @document_type_method.call(@model)
82
+ end
83
+
84
+ def mappings(&block)
85
+ @mappings ||= {}
86
+ @mappings = DSL::Mapping.new(&block).to_hash if block_given?
87
+ @mappings
88
+ end
89
+
90
+ def index_scope
91
+ @model.all
92
+ end
93
+
94
+ def settings(data = {})
95
+ @settings ||= {}
96
+ @settings.merge! data
97
+ @settings
98
+ end
99
+
100
+
101
+ def reindex
102
+ alias_name = index_name
103
+ new_index_name = alias_name + "_" + Time.now.strftime("%Y%m%d%H%M%S%L")
104
+
105
+ document_mappings = {}
106
+ document_mappings[document_type] = mappings
107
+ client.indices.create index: new_index_name,
108
+ body: {
109
+ settings: settings,
110
+ mappings: document_mappings
111
+ }
112
+
113
+ if client.indices.exists_alias(name: alias_name)
114
+ existing_alias = client.indices.get_alias(name: alias_name)
115
+ Importer.new(index_scope, new_index_name, document_type).execute!
116
+ client.indices.delete index: existing_alias.keys
117
+ client.indices.put_alias index: new_index_name, name: alias_name
118
+ else
119
+ client.indices.put_alias index: new_index_name, name: alias_name
120
+ Importer.new(index_scope, new_index_name, document_type).execute!
121
+ end
122
+
123
+ end
124
+ end
125
+
126
+
127
+ module Model
128
+ extend ActiveSupport::Concern
129
+
130
+ def es
131
+ @es ||= ModelClient.new(self)
132
+ end
133
+
134
+ def as_indexed_json
135
+ as_json
136
+ end
137
+
138
+
139
+ included do
140
+ after_commit lambda { es.index }, on: [:update, :create]
141
+ after_commit lambda { es.delete }, on: :destroy
142
+ end
143
+
144
+ module ClassMethods
145
+ def supple &block
146
+ @supple ||= Supple::Config.new(self)
147
+ @supple.instance_eval(&block) if block_given?
148
+ @supple
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,59 @@
1
+ module Supple
2
+ module DSL
3
+ class Mapping
4
+ def initialize(data = {}, &block)
5
+ @data = data
6
+ @data[property_key] ||= {}
7
+ instance_eval(&block) if block_given?
8
+ end
9
+
10
+ def prop(name, options = {}, &block)
11
+ if block_given?
12
+ @data[property_key][name] = Mapping.new(options).instance_eval(&block).to_hash
13
+ end
14
+ @data[property_key][name] = options
15
+ end
16
+
17
+ def dynamic_template(name, &block)
18
+ @data[:dynamic_templates] ||= []
19
+ dt = DynamicTemplate.new(name, &block)
20
+ @data[:dynamic_templates] << dt.to_hash
21
+ end
22
+
23
+ def to_hash
24
+ @data
25
+ end
26
+
27
+ private
28
+
29
+ def property_key
30
+ @data[:type].to_s == 'multi_field' ? :fields : :properties
31
+ end
32
+ end
33
+
34
+ class DynamicTemplate
35
+ def initialize(name, options = {}, &block)
36
+ @name = name
37
+ @options = options
38
+ @data = {}
39
+ instance_eval(&block) if block_given?
40
+ end
41
+
42
+ [:match, :unmatch, :match_mapping_type, :path_match, :path_unmatch, :match_pattern].each do |meth|
43
+ define_method(meth) do |val|
44
+ @data[meth] = val
45
+ end
46
+ end
47
+ def mapping(data = {}, &block)
48
+ mapping = Mapping.new(data)
49
+ mapping.instance_eval(&block) if block_given?
50
+ @data[:mapping] = mapping.to_hash
51
+ end
52
+
53
+ def to_hash
54
+ @options[@name] = @data
55
+ @options
56
+ end
57
+ end
58
+ end
59
+ end