flex 0.4.2 → 1.0.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.
Files changed (78) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +46 -7
  3. data/VERSION +1 -1
  4. data/flex.gemspec +13 -19
  5. data/lib/flex.rb +66 -392
  6. data/lib/flex/api_stubs.rb +1268 -0
  7. data/lib/flex/api_templates/cluster_api.yml +94 -0
  8. data/lib/flex/api_templates/core_api.yml +202 -0
  9. data/lib/flex/api_templates/indices_api.yml +304 -0
  10. data/lib/flex/class_proxy/base.rb +20 -6
  11. data/lib/flex/class_proxy/templates.rb +97 -0
  12. data/lib/flex/class_proxy/templates/doc.rb +91 -0
  13. data/lib/flex/class_proxy/templates/search.rb +72 -0
  14. data/lib/flex/configuration.rb +17 -49
  15. data/lib/flex/deprecation.rb +153 -0
  16. data/lib/flex/errors.rb +2 -1
  17. data/lib/flex/http_clients/base.rb +15 -0
  18. data/lib/flex/http_clients/loader.rb +51 -0
  19. data/lib/flex/http_clients/patron.rb +9 -7
  20. data/lib/flex/http_clients/rest_client.rb +6 -8
  21. data/lib/flex/logger.rb +24 -3
  22. data/lib/flex/prog_bar.rb +11 -6
  23. data/lib/flex/rails.rb +1 -13
  24. data/lib/flex/result.rb +8 -2
  25. data/lib/flex/result/document.rb +42 -13
  26. data/lib/flex/result/multi_get.rb +24 -0
  27. data/lib/flex/result/search.rb +1 -24
  28. data/lib/flex/struct/array.rb +25 -0
  29. data/lib/flex/struct/hash.rb +105 -0
  30. data/lib/flex/{result/collection.rb → struct/paginable.rb} +16 -9
  31. data/lib/flex/struct/prunable.rb +60 -0
  32. data/lib/flex/struct/symbolize.rb +27 -0
  33. data/lib/flex/tasks.rb +26 -86
  34. data/lib/flex/template.rb +60 -120
  35. data/lib/flex/template/common.rb +42 -0
  36. data/lib/flex/template/logger.rb +66 -0
  37. data/lib/flex/template/partial.rb +12 -15
  38. data/lib/flex/template/search.rb +6 -6
  39. data/lib/flex/template/slim_search.rb +1 -1
  40. data/lib/flex/template/tags.rb +19 -9
  41. data/lib/flex/templates.rb +20 -0
  42. data/lib/flex/utility_methods.rb +80 -89
  43. data/lib/flex/utils.rb +68 -25
  44. data/lib/flex/variables.rb +55 -4
  45. data/lib/tasks.rake +28 -0
  46. metadata +61 -85
  47. data/bin/flexes +0 -174
  48. data/lib/flex/api_methods.yml +0 -108
  49. data/lib/flex/class_proxy/loader.rb +0 -102
  50. data/lib/flex/class_proxy/model.rb +0 -45
  51. data/lib/flex/class_proxy/model_sync.rb +0 -23
  52. data/lib/flex/class_proxy/related_model.rb +0 -23
  53. data/lib/flex/instance_proxy/base.rb +0 -29
  54. data/lib/flex/instance_proxy/model.rb +0 -102
  55. data/lib/flex/instance_proxy/related_model.rb +0 -7
  56. data/lib/flex/loader.rb +0 -18
  57. data/lib/flex/manager.rb +0 -61
  58. data/lib/flex/model.rb +0 -24
  59. data/lib/flex/rails/engine.rb +0 -23
  60. data/lib/flex/rails/helper.rb +0 -16
  61. data/lib/flex/related_model.rb +0 -16
  62. data/lib/flex/result/indifferent_access.rb +0 -11
  63. data/lib/flex/result/source_document.rb +0 -63
  64. data/lib/flex/result/source_search.rb +0 -32
  65. data/lib/flex/structure/indifferent_access.rb +0 -44
  66. data/lib/flex/structure/mergeable.rb +0 -21
  67. data/lib/flex/template/base.rb +0 -41
  68. data/lib/flex/template/info.rb +0 -68
  69. data/lib/generators/flex/setup/setup_generator.rb +0 -48
  70. data/lib/generators/flex/setup/templates/flex_config.yml +0 -16
  71. data/lib/generators/flex/setup/templates/flex_dir/es.rb.erb +0 -18
  72. data/lib/generators/flex/setup/templates/flex_dir/es.yml.erb +0 -19
  73. data/lib/generators/flex/setup/templates/flex_dir/es_extender.rb.erb +0 -17
  74. data/lib/generators/flex/setup/templates/flex_initializer.rb.erb +0 -44
  75. data/lib/tasks/index.rake +0 -17
  76. data/test/flex.irt +0 -143
  77. data/test/flex/configuration.irt +0 -53
  78. data/test/irt_helper.rb +0 -12
@@ -1,15 +1,29 @@
1
1
  module Flex
2
2
  module ClassProxy
3
-
4
3
  class Base
5
- attr_reader :host_class
4
+
6
5
  attr_accessor :variables
7
6
 
8
- def initialize(host_class)
9
- @host_class = host_class
10
- @variables = Variables.new
7
+ def initialize(context, vars={})
8
+ @variables = Vars.new({:context => context,
9
+ :index => Conf.variables[:index]}.merge(vars))
11
10
  end
12
- end
13
11
 
12
+ def init; end
13
+
14
+ [:context, :index, :type].each do |meth|
15
+ define_method meth do
16
+ variables[meth]
17
+ end
18
+ define_method :"#{meth}=" do |val|
19
+ variables[meth] = val
20
+ end
21
+ end
22
+
23
+ def refresh_index
24
+ Flex.refresh_index :index => index
25
+ end
26
+
27
+ end
14
28
  end
15
29
  end
@@ -0,0 +1,97 @@
1
+ module Flex
2
+ module ClassProxy
3
+ module Templates
4
+
5
+ attr_reader :templates, :partials
6
+ include Doc
7
+ include Search
8
+
9
+ def init
10
+ @sources = []
11
+ @templates = {}
12
+ @partials = {}
13
+ end
14
+
15
+ # accepts a path to a file or YAML string
16
+ def load_source_for(klass, source, source_vars)
17
+ if source.nil? || source !~ /\n/m
18
+ paths = [ "#{Conf.flex_dir}/#{source}.yml",
19
+ "#{Conf.flex_dir}/#{Utils.class_name_to_type(context.name)}.yml",
20
+ source.to_s ]
21
+ source = paths.find {|p| File.exist?(p)}
22
+ end
23
+ raise ArgumentError, "expected a string, got #{source.inspect}" \
24
+ unless source.is_a?(String)
25
+ @sources << [klass, source, source_vars]
26
+ do_load_source(klass, source, source_vars)
27
+ # fixes the legacy empty stubs, which should call super instead
28
+ @templates.keys.each do |name|
29
+ meta_context.send(:define_method, name){|*vars| super *vars }
30
+ end
31
+ end
32
+
33
+ # loads a Generic Template source
34
+ def load_source(source=nil, source_vars=nil)
35
+ load_source_for(Template, source, source_vars)
36
+ end
37
+
38
+ # loads a Search Template source
39
+ def load_search_source(source=nil, source_vars=nil)
40
+ load_source_for(Template::Search, source, source_vars)
41
+ end
42
+
43
+ # loads a SlimSearch Template source
44
+ def load_slim_search_source(source=nil, source_vars=nil)
45
+ load_source_for(Template::SlimSearch, source, source_vars)
46
+ end
47
+
48
+ # reloads the sources (useful in the console and used internally)
49
+ def reload!
50
+ @sources.each {|k,s,v| do_load_source(k,s,v)}
51
+ end
52
+
53
+ def wrap(*methods, &block)
54
+ methods = templates.keys if methods.empty?
55
+ methods.each do |name|
56
+ raise MissingTemplateMethodError, "#{name} is not a template method" \
57
+ unless templates.include?(name)
58
+ meta_context.send(:define_method, name, &block)
59
+ end
60
+ end
61
+
62
+ def render(name, *vars)
63
+ templates[name].render(*vars)
64
+ end
65
+
66
+ private
67
+
68
+ def do_load_source(klass, source, source_vars)
69
+ source = Utils.erb_process(source) unless source.match("\n") # skips non-path
70
+ hash = Utils.parse_source(source)
71
+ Utils.delete_allcaps_keys(hash).each do |name, args|
72
+ define_template klass, name, args, source_vars
73
+ end
74
+ end
75
+
76
+ def define_template(klass, name, args, source_vars)
77
+ name = name.to_sym
78
+ args = [args] unless args.is_a?(Array)
79
+ if name.to_s[0] == '_' # partial
80
+ partials[name] = Template::Partial.new(*args).setup(self, name)
81
+ else
82
+ templates[name] = klass.new(*args).setup(self, name, source_vars)
83
+ context::FlexTemplateMethods.send(:define_method, name) do |*vars|
84
+ raise ArgumentError, "#{flex.context}.#{name} expects a list of Hashes, got #{vars.map(&:inspect).join(', ')}" \
85
+ unless vars.all?{|i| i.nil? || i.is_a?(Hash)}
86
+ flex.render(name,*vars)
87
+ end
88
+ end
89
+ end
90
+
91
+ def meta_context
92
+ class << context; self end
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,91 @@
1
+ module Flex
2
+ module ClassProxy
3
+ module Templates
4
+ module Doc
5
+
6
+ def doc(*names)
7
+ names = templates.keys if names.empty?
8
+ doc = "\n"
9
+ names.each do |name|
10
+ next unless templates.include?(name)
11
+ block = ''
12
+ temp = templates[name]
13
+ meth_call = [context, name].join('.')
14
+ block << <<-meth_call
15
+ ########## #{meth_call} ##########
16
+ #{'-' * temp.class.to_s.length}
17
+ #{temp.class}
18
+ #{temp.to_source}
19
+ meth_call
20
+ temp.partials.each do |par_name|
21
+ par = partials[par_name]
22
+ block << <<-partial
23
+ #{'-' * par.class.to_s.length}
24
+ #{par.class}
25
+ #{par.to_source}
26
+ partial
27
+ end
28
+ block << "\nUsage:\n"
29
+ block << build_usage(meth_call, temp)
30
+ block << "\n "
31
+ doc << block.split("\n").map{|l| '# ' + l}.join("\n")
32
+ doc << <<-meth.gsub(/^ {14}/m,'')
33
+
34
+ def #{meth_call}(*vars)
35
+ ## this is a stub, used for reference
36
+ super
37
+ end
38
+
39
+ meth
40
+ end
41
+ puts doc
42
+ end
43
+
44
+ def usage(name)
45
+ meth_call = [context, name].join('.')
46
+ puts build_usage(meth_call, templates[name])
47
+ end
48
+
49
+ private
50
+
51
+ def build_usage(meth_call, temp)
52
+ variables = temp.instance_eval do
53
+ interpolate
54
+ @base_variables.deep_merge @host_flex && @host_flex.variables, @temp_variables
55
+ end
56
+ all_tags = temp.tags + temp.partials
57
+ return meth_call if all_tags.size == 0
58
+ lines = all_tags.map do |t|
59
+ comments = 'partial' if t.to_s[0] == '_'
60
+ line = ['', t.inspect]
61
+ line + if variables.has_key?(t)
62
+ ["#{variables[t].inspect},", comments_to_s(comments)]
63
+ else
64
+ ["#{to_code(t)},", comments_to_s(comments, 'required')]
65
+ end
66
+ end
67
+ lines.sort! { |a,b| b[3] <=> a[3] }
68
+ lines.first[0] = meth_call
69
+ lines.last[2].chop!
70
+ max = lines.transpose.map { |c| c.map(&:length).max }
71
+ lines.map { |line| "%-#{max[0]}s %-#{max[1]}s => %-#{max[2]}s %s" % line }.join("\n")
72
+ end
73
+
74
+ def comments_to_s(*comments)
75
+ comments = comments.compact
76
+ return '' if comments == []
77
+ "# #{comments.join(' ')}"
78
+ end
79
+
80
+ def to_code(name)
81
+ keys = name.to_s.split('.').map{|s| s =~ /^[0..9]+$/ ? s.to_i : s.to_sym}
82
+ code = keys.shift.to_s
83
+ return code if keys.empty?
84
+ keys.each{|k| code << "[#{k.inspect}]"}
85
+ code
86
+ end
87
+
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,72 @@
1
+ module Flex
2
+ module ClassProxy
3
+ module Templates
4
+ module Search
5
+
6
+ def define_search(name, source, source_vars=nil)
7
+ args = Utils.parse_source(source)
8
+ send :define_template, Template::Search, name, args, source_vars
9
+ end
10
+
11
+ # http://www.elasticsearch.org/guide/reference/api/multi-search.html
12
+ # requests can be an array of arrays: [[:template1, variable_hash1], [template2, variable_hash2]]
13
+ # or a hash {:template1 => variable_hash1, template2 => variable_hash2}
14
+ # The variables are an hash of variables that will be used to render the msearch template
15
+ # the array of result is at <result>.responses
16
+ def multi_search(requests, *variables)
17
+ requests = requests.map { |name, vars| [name, vars] } if requests.is_a?(Hash)
18
+ lines = requests.map { |name, vars| templates[name].to_msearch(vars) }.join()
19
+ template = Template.new('GET', '/<<index>>/<<type>>/_msearch') # no setup flex so raw_result
20
+ template.send(:do_render, *variables, :data => lines) do |http_response|
21
+ responses = []
22
+ es_response = MultiJson.decode(http_response.body)
23
+ es_response['responses'].each_with_index do |raw_result, i|
24
+ name, vars = requests[i]
25
+ int = templates[name].interpolate(vars, strict=true)
26
+ result = Result.new(templates[name], int[:vars], http_response, raw_result)
27
+ responses << result.to_flex_result
28
+ end
29
+ es_response['responses'] = responses
30
+ def es_response.responses
31
+ self['responses']
32
+ end
33
+ es_response
34
+ end
35
+ end
36
+
37
+ # implements search_type=scan (http://www.elasticsearch.org/guide/reference/api/search/search-type.html)
38
+ def scan_search(template, *vars, &block)
39
+ user_raw_result = vars.any?{|v| v[:raw_result]}
40
+ scroll = '5m'
41
+ search_vars = Vars.new({:params => { :search_type => 'scan',
42
+ :scroll => scroll,
43
+ :size => 50 },
44
+ :raw_result => true}, *vars)
45
+ search_temp = template.is_a?(Flex::Template) ? template : templates[template]
46
+
47
+ scroll_vars = Vars.new({:params => { :scroll => scroll },
48
+ :raw_result => true}, variables, *vars)
49
+ scroll_temp = Flex::Template.new( :get,
50
+ '/_search/scroll',
51
+ nil,
52
+ scroll_vars )
53
+ search_res = search_temp.render search_vars
54
+ scroll_id = search_res['_scroll_id']
55
+ while (result = scroll_temp.render(:data => scroll_id)) do
56
+ break if result['hits']['hits'].empty?
57
+ scroll_id = result['_scroll_id']
58
+ result.variables[:raw_result] = user_raw_result
59
+ block.call result.to_flex_result(force=true)
60
+ end
61
+ end
62
+
63
+ # implements search_type=count (http://www.elasticsearch.org/guide/reference/api/search/search-type.html)
64
+ def count_search(template, *vars)
65
+ template = template.is_a?(Flex::Template) ? template : templates[template]
66
+ template.render Vars.new({:params => {:search_type => 'count'}, :raw_result => true}, *vars)
67
+ end
68
+
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,57 +1,25 @@
1
1
  module Flex
2
- class Struct < OpenStruct
3
2
 
4
- def configure
5
- yield self
6
- end
3
+ Configuration = OpenStruct.new :result_extenders => [ Result::Document,
4
+ Result::Search,
5
+ Result::MultiGet,
6
+ Result::Bulk ],
7
+ :logger => Logger.new(STDERR),
8
+ :variables => Vars.new( :index => nil,
9
+ :type => nil,
10
+ :params => {},
11
+ :no_pruning => [] ),
12
+ :config_file => './config/flex.yml',
13
+ :flex_dir => './flex',
14
+ :http_client => HttpClients::Loader.new_http_client
7
15
 
8
- end
16
+ # shorter alias
17
+ Conf = Configuration
9
18
 
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
19
+ Conf.instance_eval do
20
+ def configure
21
+ yield self
34
22
  end
35
23
  end
36
- private :load_http_client
37
24
 
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 => [] ),
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 => false,
54
- :debug_result => true,
55
- :debug_to_curl => false,
56
- :raise_proc => proc{|response| response.status >= 400}
57
25
  end
@@ -0,0 +1,153 @@
1
+ module Flex
2
+
3
+ module Deprecation
4
+
5
+ extend self
6
+
7
+ def warn(old, new, called=1)
8
+ message = "#{old} is deprecated in favour of #{new}, and will be removed in a next version "
9
+ message << "(called at: #{caller[called]})" if called
10
+ Conf.logger.warn message
11
+ end
12
+
13
+ module Module
14
+ def extended(obj)
15
+ Deprecation.warn(self, self::NEW_MODULE, 2)
16
+ obj.extend self::NEW_MODULE
17
+ end
18
+ def included(base)
19
+ Deprecation.warn(self, self::NEW_MODULE, 2)
20
+ base.send :include, self::NEW_MODULE
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ ### Deprecation of Flex methods ###
27
+
28
+ def info(*names)
29
+ Deprecation.warn 'Flex.info', 'Flex.doc'
30
+ doc *names
31
+ end
32
+
33
+ def process_bulk(options={})
34
+ Deprecation.warn 'Flex.process_bulk(:collection => collection)', 'Flex.post_bulk_collection(collection, options)'
35
+ post_bulk_collection(options.delete(:collection), options)
36
+ end
37
+
38
+ def import_collection(collection, options={})
39
+ Deprecation.warn 'Flex.import_collection', 'Flex.post_bulk_collection'
40
+ post_bulk_collection(collection, options.merge(:action => 'index'))
41
+ end
42
+
43
+ def delete_collection(collection, options={})
44
+ Deprecation.warn 'Flex.delete_collection(collection)', 'Flex.post_bulk_collection(collection, :action => "delete")'
45
+ post_bulk_collection(collection, options.merge(:action => 'delete'))
46
+ end
47
+
48
+ def bulk(*vars)
49
+ Deprecation.warn 'Flex.bulk(:lines => lines_bulk_string)', 'Flex.post_bulk_string(:bulk_string => lines_bulk_string)'
50
+ vars = Vars.new(*vars)
51
+ post_bulk_string(:bulk_string => vars[:lines])
52
+ end
53
+
54
+
55
+ ### Deprecation of Configuration methods ###
56
+
57
+ Configuration.instance_eval do
58
+ # temprary deprecation warnings
59
+ def base_uri
60
+ Deprecation.warn 'Flex::Configuration.base_uri', 'Flex::Configuration.http_client.base_uri'
61
+ http_client.base_uri
62
+ end
63
+ def base_uri=(val)
64
+ Deprecation.warn 'Flex::Configuration.base_uri=', 'Flex::Configuration.http_client.base_uri='
65
+ http_client.base_uri = val
66
+ end
67
+ def http_client_options
68
+ Deprecation.warn 'Flex::Configuration.http_client_options', 'Flex::Configuration.http_client.options'
69
+ http_client.options
70
+ end
71
+ def http_client_options=(val)
72
+ Deprecation.warn 'Flex::Configuration.http_client_options=', 'Flex::Configuration.http_client.options='
73
+ http_client.options = val
74
+ end
75
+ def raise_proc
76
+ Deprecation.warn 'Flex::Configuration.raise_proc', 'Flex::Configuration.http_client.raise_proc'
77
+ http_client.raise_proc
78
+ end
79
+ def raise_proc=(val)
80
+ Deprecation.warn 'Flex::Configuration.raise_proc=', 'Flex::Configuration.http_client.raise_proc='
81
+ http_client.raise_proc = val
82
+ end
83
+ end
84
+
85
+
86
+ class Variables
87
+ def add(*hashes)
88
+ Deprecation.warn 'Flex::Variables#add', 'Flex::Variables#deep_merge!'
89
+ replace deep_merge(*hashes)
90
+ end
91
+ end
92
+
93
+
94
+ module Struct::Mergeable
95
+ def add(*hashes)
96
+ Deprecation.warn 'Flex::Variables#add', 'Variables#deep_merge!'
97
+ replace deep_merge(*hashes)
98
+ end
99
+ end
100
+
101
+
102
+ module Loader
103
+ NEW_MODULE = Templates
104
+ extend Deprecation::Module
105
+ end
106
+
107
+
108
+ module ClassProxy::Loader
109
+ NEW_MODULE = ClassProxy::Templates
110
+ extend Deprecation::Module
111
+ end
112
+
113
+
114
+ module ClassProxy::Templates
115
+ module Doc
116
+ def info(*names)
117
+ Deprecation.warn 'flex.info', 'flex.doc'
118
+ doc *names
119
+ end
120
+ end
121
+ end
122
+
123
+
124
+ module Result::Collection
125
+ NEW_MODULE = Struct::Paginable
126
+ extend Deprecation::Module
127
+ end
128
+
129
+
130
+ module Model
131
+ def self.included(base)
132
+ if defined?(Flex::ModelIndexer)
133
+ Deprecation.warn 'Flex::Model', 'Flex::ModelIndexer'
134
+ base.send :include, Flex::ModelIndexer
135
+ else
136
+ raise NotImplementedError, %(Flex does not include "Flex::Model" anymore. Please, require the "flex-models" gem, and include "Flex::ModelIndexer" instead.)
137
+ end
138
+ end
139
+ end
140
+
141
+
142
+ module RelatedModel
143
+ def self.included(base)
144
+ if defined?(Flex::ModelSyncer)
145
+ Deprecation.warn 'Flex::RelatedModel', 'Flex::ModelSyncer'
146
+ base.send :include, Flex::ModelSyncer
147
+ else
148
+ raise NotImplementedError, %(Flex does not include "Flex::RelatedModel" anymore. Please, require the "flex-models" gem, and include "Flex::ModelSyncer" instead.)
149
+ end
150
+ end
151
+ end
152
+
153
+ end