flex 0.1.0
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/LICENSE +20 -0
- data/README.md +20 -0
- data/VERSION +1 -0
- data/flex.gemspec +43 -0
- data/lib/flex.rb +418 -0
- data/lib/flex/api_methods.yml +108 -0
- data/lib/flex/class_proxy.rb +12 -0
- data/lib/flex/configuration.rb +57 -0
- data/lib/flex/errors.rb +42 -0
- data/lib/flex/http_clients/patron.rb +27 -0
- data/lib/flex/http_clients/rest_client.rb +38 -0
- data/lib/flex/loader.rb +116 -0
- data/lib/flex/logger.rb +16 -0
- data/lib/flex/model.rb +24 -0
- data/lib/flex/model/class_proxy.rb +45 -0
- data/lib/flex/model/instance_proxy.rb +101 -0
- data/lib/flex/model/manager.rb +67 -0
- data/lib/flex/rails.rb +12 -0
- data/lib/flex/rails/engine.rb +23 -0
- data/lib/flex/rails/helper.rb +16 -0
- data/lib/flex/related_model.rb +16 -0
- data/lib/flex/related_model/class_proxy.rb +23 -0
- data/lib/flex/related_model/class_sync.rb +23 -0
- data/lib/flex/related_model/instance_proxy.rb +28 -0
- data/lib/flex/result.rb +18 -0
- data/lib/flex/result/bulk.rb +20 -0
- data/lib/flex/result/collection.rb +51 -0
- data/lib/flex/result/document.rb +38 -0
- data/lib/flex/result/indifferent_access.rb +11 -0
- data/lib/flex/result/search.rb +51 -0
- data/lib/flex/result/source_document.rb +63 -0
- data/lib/flex/result/source_search.rb +32 -0
- data/lib/flex/structure/indifferent_access.rb +44 -0
- data/lib/flex/structure/mergeable.rb +21 -0
- data/lib/flex/tasks.rb +141 -0
- data/lib/flex/template.rb +187 -0
- data/lib/flex/template/base.rb +29 -0
- data/lib/flex/template/info.rb +50 -0
- data/lib/flex/template/partial.rb +31 -0
- data/lib/flex/template/search.rb +30 -0
- data/lib/flex/template/slim_search.rb +13 -0
- data/lib/flex/template/tags.rb +46 -0
- data/lib/flex/utility_methods.rb +140 -0
- data/lib/flex/utils.rb +59 -0
- data/lib/flex/variables.rb +11 -0
- data/lib/generators/flex/setup/setup_generator.rb +51 -0
- data/lib/generators/flex/setup/templates/flex_config.yml +16 -0
- data/lib/generators/flex/setup/templates/flex_dir/es.rb.erb +18 -0
- data/lib/generators/flex/setup/templates/flex_dir/es.yml.erb +19 -0
- data/lib/generators/flex/setup/templates/flex_dir/es_extender.rb.erb +17 -0
- data/lib/generators/flex/setup/templates/flex_initializer.rb.erb +44 -0
- data/lib/tasks/index.rake +23 -0
- data/test/flex.irt +143 -0
- data/test/flex/configuration.irt +53 -0
- data/test/irt_helper.rb +12 -0
- metadata +211 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
# These methods are available as Flex.<method> variable_hash
|
2
|
+
# you can get the updated full reference and usage example of these methods
|
3
|
+
# by just doing in the console:
|
4
|
+
# >> puts Flex.info
|
5
|
+
|
6
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-indices-exists.html
|
7
|
+
indices_exists: &exist
|
8
|
+
- HEAD
|
9
|
+
- /<<index>>
|
10
|
+
|
11
|
+
# aliased
|
12
|
+
exist?: *exist
|
13
|
+
|
14
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index.html
|
15
|
+
create_index: &create
|
16
|
+
- PUT
|
17
|
+
- /<<index>>
|
18
|
+
- settings:
|
19
|
+
number_of_shards: <<number_of_shards= 5 >>
|
20
|
+
number_of_replicas: <<number_of_replicas= 1 >>
|
21
|
+
|
22
|
+
# aliased
|
23
|
+
put_index: *create
|
24
|
+
|
25
|
+
post_index:
|
26
|
+
- POST
|
27
|
+
- /<<index>>
|
28
|
+
- settings:
|
29
|
+
number_of_shards: <<number_of_shards= 5 >>
|
30
|
+
number_of_replicas: <<number_of_replicas= 1 >>
|
31
|
+
|
32
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-get-settings.html
|
33
|
+
get_settings:
|
34
|
+
- GET
|
35
|
+
- /<<index>>/_settings
|
36
|
+
|
37
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping.html
|
38
|
+
put_mapping:
|
39
|
+
- PUT
|
40
|
+
- /<<index>>/<<type>>/_mapping
|
41
|
+
- <<type>>:
|
42
|
+
properties: <<properties>>
|
43
|
+
|
44
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-get-mapping.html
|
45
|
+
get_mapping:
|
46
|
+
- GET
|
47
|
+
- /<<index>>/<<type>>/_mapping
|
48
|
+
|
49
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-mapping.html
|
50
|
+
delete_mapping:
|
51
|
+
- DELETE
|
52
|
+
- /<<index>>/<<type>>
|
53
|
+
|
54
|
+
# http://www.elasticsearch.org/guide/reference/api/delete.html
|
55
|
+
delete_index:
|
56
|
+
- DELETE
|
57
|
+
- /<<index>>
|
58
|
+
|
59
|
+
# http://www.elasticsearch.org/guide/reference/api/delete-by-query.html
|
60
|
+
delete_by_query:
|
61
|
+
- DELETE
|
62
|
+
- /<<index>>/<<type>>/_query
|
63
|
+
# pass :data variable query if you need
|
64
|
+
|
65
|
+
# http://www.elasticsearch.org/guide/reference/api/bulk.html
|
66
|
+
bulk:
|
67
|
+
- POST
|
68
|
+
- /_bulk
|
69
|
+
- << lines >>
|
70
|
+
|
71
|
+
# http://www.elasticsearch.org/guide/reference/api/count.html
|
72
|
+
count:
|
73
|
+
- GET
|
74
|
+
- /<<index>>/<<type>>/_count
|
75
|
+
# pass :data structure if you need
|
76
|
+
|
77
|
+
# http://www.elasticsearch.org/guide/reference/api/admin-indices-stats.html
|
78
|
+
stats:
|
79
|
+
- GET
|
80
|
+
- /<<index>>/_stats/<<end_point= ~ >>
|
81
|
+
|
82
|
+
# You must pass the :data variable
|
83
|
+
store: &store
|
84
|
+
- PUT
|
85
|
+
- /<<index>>/<<type>>/<<id>>
|
86
|
+
|
87
|
+
# alias for symmetry with post_store
|
88
|
+
put_store: *store
|
89
|
+
|
90
|
+
# id is set by ES; you must pass :data
|
91
|
+
post_store:
|
92
|
+
- POST
|
93
|
+
- /<<index>>/<<type>>
|
94
|
+
|
95
|
+
remove:
|
96
|
+
- DELETE
|
97
|
+
- /<<index>>/<<type>>/<<id>>
|
98
|
+
|
99
|
+
# http://www.elasticsearch.org/guide/reference/api/get.html
|
100
|
+
get:
|
101
|
+
- GET
|
102
|
+
- /<<index>>/<<type>>/<<id>>
|
103
|
+
|
104
|
+
# http://www.elasticsearch.org/guide/reference/api/multi-get.html
|
105
|
+
multi_get:
|
106
|
+
- GET
|
107
|
+
- /<<index>>/<<type>>/_mget
|
108
|
+
- ids: << ids >>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Flex
|
2
|
+
class Struct < OpenStruct
|
3
|
+
|
4
|
+
def configure
|
5
|
+
yield self
|
6
|
+
end
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
extend self
|
11
|
+
|
12
|
+
def load_http_client
|
13
|
+
if Gem::Specification.respond_to?(:find_all_by_name)
|
14
|
+
case
|
15
|
+
# terrible way to check whether a gem is available.
|
16
|
+
# Gem.available? was just perfect: that's probably the reason it has been deprecated!
|
17
|
+
# https://github.com/rubygems/rubygems/issues/176
|
18
|
+
when Gem::Specification::find_all_by_name('patron').any?
|
19
|
+
require 'patron'
|
20
|
+
Flex::HttpClients::Patron
|
21
|
+
when Gem::Specification::find_all_by_name('rest-client').any?
|
22
|
+
require 'rest-client'
|
23
|
+
Flex::HttpClients::RestClient
|
24
|
+
end
|
25
|
+
else
|
26
|
+
case
|
27
|
+
when Gem.available?('patron')
|
28
|
+
require 'patron'
|
29
|
+
Flex::HttpClients::Patron
|
30
|
+
when Gem.available?('rest-client')
|
31
|
+
require 'rest-client'
|
32
|
+
Flex::HttpClients::RestClient
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
private :load_http_client
|
37
|
+
|
38
|
+
Configuration = Struct.new :base_uri => 'http://localhost:9200',
|
39
|
+
:result_extenders => [ Flex::Result::Document,
|
40
|
+
Flex::Result::SourceDocument,
|
41
|
+
Flex::Result::Search,
|
42
|
+
Flex::Result::SourceSearch,
|
43
|
+
Flex::Result::Bulk ],
|
44
|
+
:logger => Logger.new(STDERR),
|
45
|
+
:variables => Variables.new( :index => nil,
|
46
|
+
:type => nil,
|
47
|
+
:no_pruning => %w[match_all] ),
|
48
|
+
:flex_models => [],
|
49
|
+
:config_file => './config/flex.yml',
|
50
|
+
:flex_dir => './flex',
|
51
|
+
:http_client => load_http_client,
|
52
|
+
:http_client_options => {},
|
53
|
+
:debug => true,
|
54
|
+
:debug_result => true,
|
55
|
+
:debug_to_curl => false,
|
56
|
+
:raise_proc => proc{|response| response.status >= 400}
|
57
|
+
end
|
data/lib/flex/errors.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Flex
|
2
|
+
|
3
|
+
class ArgumentError < ArgumentError; end
|
4
|
+
class SourceError < StandardError; end
|
5
|
+
class MissingPartialError < StandardError; end
|
6
|
+
class DocumentMappingError < StandardError; end
|
7
|
+
class MissingIndexEntryError < StandardError; end
|
8
|
+
class ExistingIndexError < StandardError; end
|
9
|
+
class MissingHttpClientError < StandardError; end
|
10
|
+
class MissingParentError < StandardError; end
|
11
|
+
|
12
|
+
class HttpError < StandardError
|
13
|
+
|
14
|
+
attr_reader :response
|
15
|
+
|
16
|
+
def initialize(response, caller_line=nil)
|
17
|
+
@response = response
|
18
|
+
@caller_line = caller_line
|
19
|
+
end
|
20
|
+
|
21
|
+
def status
|
22
|
+
response.status
|
23
|
+
end
|
24
|
+
|
25
|
+
def body
|
26
|
+
response.body
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
log = "#{@caller_line}\n" if @caller_line
|
31
|
+
"#{log}#{status}: #{body}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_hash
|
35
|
+
MultiJson.decode response.body
|
36
|
+
rescue MultiJson::DecodeError
|
37
|
+
{}
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Flex
|
2
|
+
module HttpClients
|
3
|
+
module Patron
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def request(method, path, data=nil, options={})
|
7
|
+
options = Utils.deep_merge_hashes(Configuration.http_client_options, options)
|
8
|
+
options = options.merge(:data => data) if data
|
9
|
+
session.request method.to_s.downcase.to_sym, path, {}, options
|
10
|
+
rescue ::Patron::TimeoutError
|
11
|
+
session.request method.to_s.downcase.to_sym, path, {}, options
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def session
|
17
|
+
Thread.current[:flex_patron_session] ||= begin
|
18
|
+
sess = ::Patron::Session.new
|
19
|
+
sess.headers['User-Agent'] = "flex-#{Flex::VERSION}"
|
20
|
+
sess.base_url = Configuration.base_uri
|
21
|
+
sess
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Flex
|
2
|
+
module HttpClients
|
3
|
+
module RestClient
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def request(method, path, data=nil, options={})
|
7
|
+
options = Configuration.http_client_options.merge options
|
8
|
+
url = Configuration.base_uri + path
|
9
|
+
args = options.merge( :method => method.to_s.downcase.to_sym,
|
10
|
+
:url => url,
|
11
|
+
:payload => data )
|
12
|
+
response = ::RestClient::Request.new( args ).execute
|
13
|
+
extend_response(response, url)
|
14
|
+
|
15
|
+
rescue ::RestClient::ExceptionWithResponse, ::RestClient::RequestFailed => e
|
16
|
+
extend_response(e.response, url)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def extend_response(response, url)
|
22
|
+
response.extend ResponseExtension
|
23
|
+
response.url = url
|
24
|
+
response
|
25
|
+
end
|
26
|
+
|
27
|
+
module ResponseExtension
|
28
|
+
attr_accessor :url
|
29
|
+
|
30
|
+
def status
|
31
|
+
code.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/flex/loader.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Flex
|
2
|
+
module Loader
|
3
|
+
|
4
|
+
extend self
|
5
|
+
attr_accessor :host_classes
|
6
|
+
@host_classes = []
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
Flex::Loader.host_classes |= [base]
|
11
|
+
class << self; attr_reader :flex end
|
12
|
+
@flex = Flex::Loader::ClassProxy.new(base)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ClassProxy < Flex::ClassProxy
|
17
|
+
attr_reader :templates, :partials
|
18
|
+
|
19
|
+
include Template::Info
|
20
|
+
|
21
|
+
def initialize(base)
|
22
|
+
super
|
23
|
+
@sources = []
|
24
|
+
@templates = {}
|
25
|
+
@partials = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# accepts a path to a file or YAML string
|
29
|
+
def load_source_for(klass, source, source_vars)
|
30
|
+
if source.nil? || source != /\n/
|
31
|
+
paths = [ "#{Configuration.flex_dir}/#{source}.yml",
|
32
|
+
"#{Configuration.flex_dir}/#{Model::Manager.class_name_to_type(host_class.name)}.yml",
|
33
|
+
source ]
|
34
|
+
source = paths.find {|p| File.exist?(p)}
|
35
|
+
end
|
36
|
+
raise ArgumentError, "expected a string (got #{source.inspect})." \
|
37
|
+
unless source.is_a?(String)
|
38
|
+
@sources << [klass, source, source_vars]
|
39
|
+
do_load_source(klass, source, source_vars)
|
40
|
+
end
|
41
|
+
|
42
|
+
# loads a Generic Template source
|
43
|
+
def load_source(source=nil, source_vars=nil)
|
44
|
+
load_source_for(Template, source, source_vars)
|
45
|
+
end
|
46
|
+
|
47
|
+
# loads a Search Template source
|
48
|
+
def load_search_source(source=nil, source_vars=nil)
|
49
|
+
load_source_for(Template::Search, source, source_vars)
|
50
|
+
end
|
51
|
+
|
52
|
+
# loads a SlimSearch Template source
|
53
|
+
def load_slim_search_source(source=nil, source_vars=nil)
|
54
|
+
load_source_for(Template::SlimSearch, source, source_vars)
|
55
|
+
end
|
56
|
+
|
57
|
+
# reloads the sources (useful in the console and used internally)
|
58
|
+
def reload!
|
59
|
+
@sources.each {|k,s,v| do_load_source(k,s,v)}
|
60
|
+
end
|
61
|
+
|
62
|
+
# adds a template instance and defines the template method in the host class
|
63
|
+
def add_template(name, template)
|
64
|
+
templates[name] = template
|
65
|
+
# no define_singleton_method in 1.8.7
|
66
|
+
host_class.instance_eval <<-ruby, __FILE__, __LINE__ + 1
|
67
|
+
def #{name}(vars={})
|
68
|
+
raise ArgumentError, "#{host_class}.#{name} expects a Hash (got \#{vars.inspect})" unless vars.is_a?(Hash)
|
69
|
+
#{host_class.respond_to?(:preprocess_variables) && 'preprocess_variables(vars)'}
|
70
|
+
flex.templates[:#{name}].render(vars)
|
71
|
+
end
|
72
|
+
ruby
|
73
|
+
end
|
74
|
+
|
75
|
+
# http://www.elasticsearch.org/guide/reference/api/multi-search.html
|
76
|
+
# request may be a hash with the templates names as keys and the variable hash as value
|
77
|
+
# or you can also use an array of arrays.
|
78
|
+
# The variables are an hash of variables that will be used to render the msearch template
|
79
|
+
def multi_search(requests, variables={})
|
80
|
+
lines = requests.map { |name, vars| templates[name].to_msearch(vars) }.join()
|
81
|
+
template = Template.new('GET', '/<<index>>/<<type>>/_msearch')
|
82
|
+
template.send(:do_render, variables.merge(:data => lines)) do |http_response|
|
83
|
+
responses = []
|
84
|
+
es_response = MultiJson.decode(http_response.body)
|
85
|
+
es_response['responses'].each_with_index do |result, i|
|
86
|
+
responses << Result.new(templates[requests[i].first], requests[i].last, http_response, result)
|
87
|
+
end
|
88
|
+
es_response['responses'] = responses
|
89
|
+
def es_response.responses
|
90
|
+
self['responses']
|
91
|
+
end
|
92
|
+
es_response
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def do_load_source(klass, source, source_vars)
|
99
|
+
source = Utils.erb_process(source) unless source.match("\n") # skips non-path
|
100
|
+
hash = Utils.data_from_source(source)
|
101
|
+
hash.delete('ANCHORS')
|
102
|
+
hash.each do |name, structure|
|
103
|
+
if name.to_s =~ /^_/ # partial
|
104
|
+
partial = Template::Partial.new(structure, self)
|
105
|
+
partials[name.to_sym] = partial
|
106
|
+
else
|
107
|
+
template = klass.new(*structure).setup(self, name, source_vars)
|
108
|
+
add_template(name.to_sym, template)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
data/lib/flex/logger.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Flex
|
4
|
+
class Logger < ::Logger
|
5
|
+
|
6
|
+
def initialize(*)
|
7
|
+
super
|
8
|
+
self.level = ::Logger::INFO
|
9
|
+
self.progname = "FLEX"
|
10
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
11
|
+
"#{msg}\n"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/flex/model.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Flex
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
class << self; attr_reader :flex end
|
7
|
+
@flex ||= Flex::Model::ClassProxy.new(base)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def flex
|
12
|
+
@flex ||= InstanceProxy.new(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def flex_source
|
16
|
+
to_hash.reject {|k| k.to_s =~ /^_*id$/}.to_json
|
17
|
+
end
|
18
|
+
|
19
|
+
def flex_indexable?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|