flex 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +20 -0
  3. data/VERSION +1 -0
  4. data/flex.gemspec +43 -0
  5. data/lib/flex.rb +418 -0
  6. data/lib/flex/api_methods.yml +108 -0
  7. data/lib/flex/class_proxy.rb +12 -0
  8. data/lib/flex/configuration.rb +57 -0
  9. data/lib/flex/errors.rb +42 -0
  10. data/lib/flex/http_clients/patron.rb +27 -0
  11. data/lib/flex/http_clients/rest_client.rb +38 -0
  12. data/lib/flex/loader.rb +116 -0
  13. data/lib/flex/logger.rb +16 -0
  14. data/lib/flex/model.rb +24 -0
  15. data/lib/flex/model/class_proxy.rb +45 -0
  16. data/lib/flex/model/instance_proxy.rb +101 -0
  17. data/lib/flex/model/manager.rb +67 -0
  18. data/lib/flex/rails.rb +12 -0
  19. data/lib/flex/rails/engine.rb +23 -0
  20. data/lib/flex/rails/helper.rb +16 -0
  21. data/lib/flex/related_model.rb +16 -0
  22. data/lib/flex/related_model/class_proxy.rb +23 -0
  23. data/lib/flex/related_model/class_sync.rb +23 -0
  24. data/lib/flex/related_model/instance_proxy.rb +28 -0
  25. data/lib/flex/result.rb +18 -0
  26. data/lib/flex/result/bulk.rb +20 -0
  27. data/lib/flex/result/collection.rb +51 -0
  28. data/lib/flex/result/document.rb +38 -0
  29. data/lib/flex/result/indifferent_access.rb +11 -0
  30. data/lib/flex/result/search.rb +51 -0
  31. data/lib/flex/result/source_document.rb +63 -0
  32. data/lib/flex/result/source_search.rb +32 -0
  33. data/lib/flex/structure/indifferent_access.rb +44 -0
  34. data/lib/flex/structure/mergeable.rb +21 -0
  35. data/lib/flex/tasks.rb +141 -0
  36. data/lib/flex/template.rb +187 -0
  37. data/lib/flex/template/base.rb +29 -0
  38. data/lib/flex/template/info.rb +50 -0
  39. data/lib/flex/template/partial.rb +31 -0
  40. data/lib/flex/template/search.rb +30 -0
  41. data/lib/flex/template/slim_search.rb +13 -0
  42. data/lib/flex/template/tags.rb +46 -0
  43. data/lib/flex/utility_methods.rb +140 -0
  44. data/lib/flex/utils.rb +59 -0
  45. data/lib/flex/variables.rb +11 -0
  46. data/lib/generators/flex/setup/setup_generator.rb +51 -0
  47. data/lib/generators/flex/setup/templates/flex_config.yml +16 -0
  48. data/lib/generators/flex/setup/templates/flex_dir/es.rb.erb +18 -0
  49. data/lib/generators/flex/setup/templates/flex_dir/es.yml.erb +19 -0
  50. data/lib/generators/flex/setup/templates/flex_dir/es_extender.rb.erb +17 -0
  51. data/lib/generators/flex/setup/templates/flex_initializer.rb.erb +44 -0
  52. data/lib/tasks/index.rake +23 -0
  53. data/test/flex.irt +143 -0
  54. data/test/flex/configuration.irt +53 -0
  55. data/test/irt_helper.rb +12 -0
  56. 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,12 @@
1
+ module Flex
2
+ class ClassProxy
3
+ attr_reader :host_class
4
+ attr_accessor :variables
5
+
6
+ def initialize(host_class)
7
+ @host_class = host_class
8
+ @variables = Variables.new
9
+ end
10
+
11
+ end
12
+ end
@@ -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
@@ -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
@@ -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
+
@@ -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