lycra 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f6b763be6e3d625f7ce696812f062ea5cb4f872
4
- data.tar.gz: 801867731e2be4d690668c6268358ce26369ae37
3
+ metadata.gz: 3ea417f626bf68c1e6f119212965332911aa6500
4
+ data.tar.gz: 66f08754c51707c08120be29fd4d9560d63683e3
5
5
  SHA512:
6
- metadata.gz: 5cbb169b8c12801e70c6ef6bdf526b90c08044f08279862a08bf835deb31f347c76f041e81ebd138ac45f28842dc331ff39b4ada881bc553fd563ffccb5bf0c4
7
- data.tar.gz: c640a28436b4039b3e01a611e9ba5c5ada95cb15d29a8510fd2a67f6545038f7c2abfcf63b7a5ea4171b137aaa9e197cc541e9be0869e7571f7892475023c694
6
+ metadata.gz: cd1f851885ead6d4fa92fded263ed0d15a8efb7ab1006a52b5b66396cba5accf9770e2bc70124bb834a539e55126dc5fa3c56f177c287a45f5a0be6960f9067a
7
+ data.tar.gz: d0decf59b1e7a67c5b18aab8dab21ac586a5aed6bd9e2dabd874b80723889c44d76af0db32fafb1ed4724a1d7c8a14efa43f479fd06633fd1e60d978c22daf3d
@@ -0,0 +1,15 @@
1
+ module Lycra
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Lycra
4
+
5
+ initializer "lycra.configure_rails_logger" do
6
+ Lycra.configure do |config|
7
+ config.logger = Rails.logger
8
+ end
9
+ end
10
+
11
+ initializer "lycra.elasticsearch.client" do |app|
12
+ Elasticsearch::Model.client = Lycra.client
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ module Lycra
2
+ class DocumentNotFoundError < StandardError
3
+ attr_reader :model
4
+
5
+ def initialize(model=nil)
6
+ @model = model
7
+
8
+ if model.nil? || model.name.nil?
9
+ msg = <<MSG
10
+ You must define a corresponding document class for all models utilizing Lycra::Model. For example, if your model is called BlogPost:
11
+
12
+ # /app/documents/blog_post_document.rb
13
+ class BlogPostDocument < Lycra::Document
14
+ index_name 'blog-posts'
15
+ end
16
+ MSG
17
+ else
18
+ msg = <<MSG
19
+ You must define a corresponding document class for your #{model.name} model. For example:
20
+
21
+ # /app/documents/#{model.name.split('::').map { |n| n.underscore }.join('/')}_document.rb
22
+ class #{model.name}Document < Lycra::Document
23
+ index_name '#{model.name.parameterize.pluralize}'
24
+ end
25
+ MSG
26
+ end
27
+
28
+ super(msg)
29
+ end
30
+ end
31
+
32
+ class UndefinedIndexError < StandardError
33
+ attr_reader :document
34
+
35
+ def initialize(document=nil)
36
+ @document = document
37
+
38
+ if document.nil?
39
+ super("You must define an index_name for your document class. Try: `index_name 'my-searchable-things'`")
40
+ else
41
+ super("You must define an index_name for your #{document.class.name}. Try: `index_name '#{subject_name.underscore.pluralize}'`")
42
+ end
43
+ end
44
+
45
+ def subject_name
46
+ if document.subject.is_a?(Class)
47
+ document.subject.name
48
+ else
49
+ document.subject.class.name
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,62 @@
1
+ module Lycra
2
+ module Model
3
+ def self.included(base)
4
+ base.send :extend, ClassMethods
5
+ base.send :include, Elasticsearch::Model
6
+ base.send :include, Elasticsearch::Model::Callbacks
7
+
8
+ base.send :lycra_document
9
+
10
+ base.send :delegate, :as_indexed_json, to: :lycra_document
11
+ end
12
+
13
+ def lycra_document
14
+ self.class.lycra_document.new(self)
15
+ end
16
+
17
+ module ClassMethods
18
+ def index_name(idx=nil)
19
+ lycra_document.index_name idx
20
+ end
21
+
22
+ def document_type(doctype=nil)
23
+ lycra_document.document_type doctype
24
+ end
25
+
26
+ def mapping(options={}, &block)
27
+ lycra_document.mapping options, &block
28
+ end
29
+ alias_method :mappings, :mapping
30
+
31
+ def lycra_document(klass=nil)
32
+ if klass.present?
33
+ if klass.respond_to?(:constantize)
34
+ @lycra_document = klass.constantize.new(self)
35
+ else
36
+ @lycra_document = klass.new(self)
37
+ end
38
+ end
39
+
40
+ @lycra_document ||= lycra_document_klass.new(self)
41
+ end
42
+
43
+ def lycra_document_klass
44
+ begin
45
+ return "#{self.name}Document".constantize
46
+ rescue NameError => e
47
+ # noop, we just continue
48
+ end
49
+
50
+ if respond_to?(:base_class) && self.base_class.name != self.name
51
+ begin
52
+ return "#{self.base_class.name}Document".constantize
53
+ rescue NameError => e
54
+ # noop, we just continue
55
+ end
56
+ end
57
+
58
+ raise Lycra::DocumentNotFoundError.new(self)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,15 @@
1
+ module Lycra
2
+ module Search
3
+ class Aggregations < Array
4
+ def to_query
5
+ return {} if empty?
6
+
7
+ # can probably inject here or be a bit more elegant?
8
+ aggregations = {}
9
+ each { |agg| aggregations.merge!(agg) }
10
+ aggregations
11
+ end
12
+ alias_method :to_q, :to_query
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,200 @@
1
+ module Lycra
2
+ module Search
3
+ module Enumerable
4
+ def self.included(base)
5
+ base.send :delegate, :count, :size, :results, :records, :total_count, to: :response
6
+ base.send :delegate, :first, to: :to_a
7
+
8
+ base.send :alias_method, :total, :total_count
9
+ end
10
+
11
+ def result_type
12
+ @result_type ||= :results
13
+ end
14
+
15
+ def as_results!
16
+ @result_type = :results
17
+ self
18
+ end
19
+
20
+ def as_records!
21
+ @result_type = :records
22
+ self
23
+ end
24
+
25
+ def as_results?
26
+ @result_type != :records
27
+ end
28
+
29
+ def as_records?
30
+ @result_type == :records
31
+ end
32
+
33
+ def decorate!
34
+ @decorated = true
35
+ self
36
+ end
37
+ alias_method :decorated!, :decorate!
38
+
39
+ def undecorate!
40
+ @decorated = false
41
+ self
42
+ end
43
+ alias_method :undecorated!, :undecorate!
44
+
45
+ def decorate?
46
+ @decorated == true
47
+ end
48
+
49
+ def undecorate?
50
+ @decorated != true
51
+ end
52
+
53
+ #### Enumeration ####
54
+
55
+ def enumerable_method
56
+ "#{'decorated_' if decorate?}#{result_type}".to_sym
57
+ end
58
+
59
+ def to_ary
60
+ if decorate?
61
+ send(enumerable_method)
62
+ else
63
+ send(enumerable_method).each do |result|
64
+ apply_transformers(result)
65
+ end.to_a
66
+ end
67
+ end
68
+ alias_method :to_a, :to_ary
69
+
70
+ def each(&block)
71
+ if decorate?
72
+ send("each_#{enumerable_method}", &block)
73
+ else
74
+ send(enumerable_method).each do |result|
75
+ apply_transformers(result)
76
+ yield(result) if block_given?
77
+ end
78
+ end
79
+ end
80
+
81
+ def map(&block)
82
+ if decorate?
83
+ send("map_#{enumerable_method}", &block)
84
+ else
85
+ send(enumerable_method).map do |result|
86
+ apply_transformers(result)
87
+ yield(result) if block_given?
88
+ end
89
+ end
90
+ end
91
+
92
+ #### Decoration & Transformations ####
93
+
94
+ def transform(&block)
95
+ (@transformers ||= []) << block
96
+ self
97
+ end
98
+
99
+ def transformers
100
+ @transformers ||= []
101
+ end
102
+
103
+ def apply_transformers(result)
104
+ transformers.each do |transformer|
105
+ transformer.call(result)
106
+ end
107
+ end
108
+
109
+ def each_decorated_results(decorator=nil, &block)
110
+ map_decorated_results(decorator, &block)
111
+ @decorated_results
112
+ end
113
+ alias_method :decorated_results, :each_decorated_results
114
+ alias_method :each_decorated_result, :each_decorated_results
115
+
116
+ def map_decorated_results(decorator=nil, &block)
117
+ mapped = []
118
+ if @decorated_results
119
+ mapped = @decorated_results.map(&block)
120
+ else
121
+ @decorated_results ||= results.map do |result|
122
+ decorated = decorate_result(result, decorator)
123
+
124
+ apply_transformers(decorated)
125
+ mapped << (block_given? ? yield(decorated) : decorated)
126
+
127
+ decorated
128
+ end
129
+ end
130
+ mapped
131
+ end
132
+
133
+ def decorate_result(result, decorator=nil)
134
+ if decorator
135
+ decorator.decorate(result)
136
+ else
137
+ SearchDecorator.decorate(result)
138
+ end
139
+ end
140
+
141
+ def each_decorated_records(decorator=nil, &block)
142
+ map_decorated_records(decorator, &block)
143
+ @decorated_records
144
+ end
145
+ alias_method :decorated_records, :each_decorated_records
146
+ alias_method :each_decorated_record, :each_decorated_records
147
+
148
+ def map_decorated_records(decorator=nil, &block)
149
+ mapped = []
150
+ if @decorated_records
151
+ mapped = @decorated_records.map(&block)
152
+ else
153
+ @decorated_records ||= records.map do |record|
154
+ decorated = decorate_record(record, decorator)
155
+
156
+ apply_transformers(decorated)
157
+ mapped << (block_given? ? yield(decorated) : decorated)
158
+
159
+ decorated
160
+ end
161
+ end
162
+ mapped
163
+ end
164
+
165
+ def decorate_record(record, decorator=nil)
166
+ if decorator
167
+ decorator.decorate(record)
168
+ else
169
+ record.decorate
170
+ end
171
+ end
172
+
173
+ def records_with_hit(&block)
174
+ @records_with_hit ||= records.map_with_hit do |record,hit|
175
+ mash = Hashie::Mash.new(record: record, hit: hit)
176
+ apply_transformers(mash)
177
+ yield(mash) if block_given?
178
+ mash
179
+ end
180
+ end
181
+
182
+ def decorated_with_hit(decorator=nil, &block)
183
+ @decorated_with_hit ||= records.map_with_hit do |record,hit|
184
+ decorated = begin
185
+ if decorator
186
+ Hashie::Mash.new(record: decorator.decorate(record), hit: hit)
187
+ else
188
+ Hashie::Mash.new(record: record.decorate, hit: hit)
189
+ end
190
+ end
191
+
192
+ apply_transformers(decorated)
193
+ yield(decorated) if block_given?
194
+
195
+ decorated
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,43 @@
1
+ module Lycra
2
+ module Search
3
+ class Filters < Array
4
+ def to_query
5
+ return {} if empty?
6
+
7
+ filters = {}
8
+ filters.merge!(must_filters) unless must_filters.empty?
9
+ filters.merge!(must_not_filters) unless must_not_filters.empty?
10
+ {bool: filters}
11
+ end
12
+ alias_method :to_q, :to_query
13
+
14
+ protected
15
+
16
+ def must_filters
17
+ queries = select { |q| q.key?(:must) || !q.key?(:must_not) }
18
+ return {} if queries.empty?
19
+
20
+ matchers = {must: []}
21
+ queries.each do |query|
22
+ if query.key?(:must)
23
+ matchers[:must].concat(query[:must])
24
+ else
25
+ matchers[:must] << query
26
+ end
27
+ end
28
+ matchers
29
+ end
30
+
31
+ def must_not_filters
32
+ queries = select { |q| q.key?(:must_not) }
33
+ return {} if queries.empty?
34
+
35
+ matchers = {must_not: []}
36
+ queries.each do |query|
37
+ matchers[:must_not].concat(query[:must_not])
38
+ end
39
+ matchers
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ module Lycra
2
+ module Search
3
+ module Pagination
4
+ def self.included(base)
5
+ base.send :delegate, :total_pages, :current_page, :limit_value, :offset_value, :last_page?, to: :response
6
+
7
+ base.send :alias_method, :pages, :total_pages
8
+ end
9
+
10
+ def page(pg=nil)
11
+ @response = response.page(pg || 1)
12
+ self
13
+ end
14
+
15
+ def per(pr=nil)
16
+ @response = response.per(pr || Lycra.configuration.per_page)
17
+ self
18
+ end
19
+
20
+ def offset(ofst=nil)
21
+ @response = response.offset(ofst || 0)
22
+ self
23
+ end
24
+
25
+ def limit(lmt=nil)
26
+ @response = response.limit(lmt || Lycra.configuration.per_page)
27
+ self
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,63 @@
1
+ module Lycra
2
+ module Search
3
+ class Query < Array
4
+ def to_query
5
+ return {} if empty? && filters.empty?
6
+
7
+ query_matcher = {}
8
+ query_matcher.merge!(must_matchers) unless must_matchers.empty?
9
+ query_matcher.merge!(should_matchers) unless should_matchers.empty?
10
+ query_filters = {filter: filters.to_query}
11
+ {
12
+ bool: query_matcher.merge(query_filters)
13
+ }
14
+ end
15
+ alias_method :to_q, :to_query
16
+
17
+ def filters
18
+ @filters ||= Lycra::Search::Filters.new
19
+ end
20
+
21
+ def filter(fltr=nil)
22
+ if fltr.present?
23
+ filters << fltr
24
+ end
25
+
26
+ self
27
+ end
28
+
29
+ def refilter(fltr)
30
+ @filters = Lycra::Search::Filters.new
31
+ filter fltr
32
+ end
33
+
34
+ protected
35
+
36
+ def must_matchers
37
+ queries = select { |q| q.key?(:must) || !q.key?(:should) }
38
+ return {} if queries.empty?
39
+
40
+ matchers = {must: []}
41
+ queries.each do |query|
42
+ if query.key?(:must)
43
+ matchers[:must].concat(query[:must])
44
+ else
45
+ matchers[:must] << query
46
+ end
47
+ end
48
+ matchers
49
+ end
50
+
51
+ def should_matchers
52
+ queries = select { |q| q.key?(:should) }
53
+ return {} if queries.empty?
54
+
55
+ matchers = {should: []}
56
+ queries.each do |query|
57
+ matchers[:should].concat(query[:should])
58
+ end
59
+ matchers
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,136 @@
1
+ module Lycra
2
+ module Search
3
+ module Scoping
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ end
7
+
8
+ def aggregations
9
+ @aggregations ||= Lycra::Search::Aggregations.new
10
+ end
11
+
12
+ def aggregate(agg=nil)
13
+ aggregations << agg unless agg.nil?
14
+ self
15
+ end
16
+ alias_method :aggregation, :aggregate
17
+
18
+ def reaggregate(agg)
19
+ @aggregations = Lycra::Search::Aggregations.new
20
+ aggregate agg
21
+ end
22
+
23
+ def filters
24
+ @filters ||= Lycra::Search::Filters.new
25
+ end
26
+
27
+ def filter(fltr=nil)
28
+ filters << fltr unless fltr.nil?
29
+ self
30
+ end
31
+
32
+ def refilter(fltr)
33
+ @filters = Lycra::Search::Filters.new
34
+ filter fltr
35
+ end
36
+
37
+ def query_filters
38
+ query.filters
39
+ end
40
+
41
+ def query_filter(fltr=nil)
42
+ query.filter fltr
43
+ self
44
+ end
45
+
46
+ def requery_filter(fltr)
47
+ query.refilter fltr
48
+ self
49
+ end
50
+
51
+ def post_filters
52
+ @post_filters ||= Lycra::Search::Filters.new
53
+ end
54
+
55
+ def post_filter(fltr=nil)
56
+ post_filters << fltr unless fltr.nil?
57
+ self
58
+ end
59
+
60
+ def repost_filter(fltr)
61
+ @post_filters = Lycra::Search::Filters.new
62
+ post_filter fltr
63
+ end
64
+
65
+ def sorter
66
+ @sorter ||= Lycra::Search::Sort.new
67
+ end
68
+
69
+ def sort(srt=nil)
70
+ sorter << srt unless srt.nil?
71
+ self
72
+ end
73
+
74
+ def resort(srt=nil)
75
+ @sorter = Lycra::Search::Sort.new
76
+ sort srt
77
+ end
78
+
79
+ def filter_by(attr, vals)
80
+ return self if vals.nil? || vals.empty?
81
+
82
+ attr_filter = {
83
+ bool: {
84
+ must: [{
85
+ or: vals.map { |val| {term: {attr.to_sym => val}} }
86
+ }]
87
+ }
88
+ }
89
+
90
+ filter(filter << attr_filter)
91
+
92
+ self
93
+ end
94
+
95
+ def where(*args)
96
+ args.extract_options!.each do |attr, vals|
97
+ vals = [vals] unless vals.is_a?(Array)
98
+ filter_by(attr, vals)
99
+ end
100
+
101
+ self
102
+ end
103
+
104
+ def find_by(*args)
105
+ unfiltered.offset(0).limit(1).where(*args).first
106
+ end
107
+
108
+ def find(id)
109
+ find_by(id: id).first
110
+ end
111
+
112
+ module ClassMethods
113
+ def self.extended(base)
114
+ # Generic Shared Scopes
115
+ base.send :scope, :all, -> { offset(0).limit(10_000) }
116
+ base.send :scope, :unfiltered, -> { refilter }
117
+ base.send :scope, :unsorted, -> { resort }
118
+ base.send :scope, :sort_by, -> (field, order=:asc) { sort({field => {order: order}}) }
119
+ base.send :scope, :by_id, -> (*objs) {
120
+ filter_by(:id, [objs].flatten.map { |obj| obj.respond_to?(:id) ? obj.id : obj })
121
+ }
122
+ end
123
+
124
+ def scope(name, block)
125
+ instance_eval do
126
+ define_method name.to_sym do |*args|
127
+ @response = nil
128
+ instance_exec *args, &block
129
+ self
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,8 @@
1
+ module Lycra
2
+ module Search
3
+ class Sort < Array
4
+ alias_method :to_query, :to_a
5
+ alias_method :to_q, :to_query
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,170 @@
1
+ require 'lycra/search/aggregations'
2
+ require 'lycra/search/filters'
3
+ require 'lycra/search/query'
4
+ require 'lycra/search/sort'
5
+ require 'lycra/search/enumerable'
6
+ require 'lycra/search/pagination'
7
+ require 'lycra/search/scoping'
8
+
9
+ module Lycra
10
+ module Search
11
+ def self.included(base)
12
+ base.send :include, Lycra::Search::Enumerable
13
+ base.send :include, Lycra::Search::Pagination
14
+ base.send :include, Lycra::Search::Scoping
15
+ base.send :extend, ClassMethods
16
+ base.send :attr_reader, :term
17
+ end
18
+
19
+ def initialize(term=nil, query: nil, filter: nil, post_filter: nil, sort: nil, models: nil, fields: nil, aggregations: nil, &block)
20
+ @term = term
21
+ @models = models
22
+ @fields = fields
23
+ self.query(block_given? ? instance_eval(&block) : query)
24
+ self.filter(filter)
25
+ self.post_filter(post_filter)
26
+ self.sort(sort)
27
+ self.aggregate(aggregations)
28
+ end
29
+
30
+ def response
31
+ @response ||= search
32
+ end
33
+
34
+ def response!
35
+ @response = search
36
+ end
37
+
38
+ def document_types
39
+ document_types ||= response.search.definition[:type]
40
+ end
41
+
42
+ def entry_name
43
+ if document_types.count == 1
44
+ document_types.first
45
+ elsif document_types.count > 1
46
+ return document_types.map(&:pluralize).to_sentence
47
+ else
48
+ 'result'
49
+ end
50
+ end
51
+
52
+ def search(qry=nil, &block)
53
+ if block_given?
54
+ Elasticsearch::Model.search(instance_eval(&block), models)
55
+ else
56
+ Elasticsearch::Model.search((qry || to_query), models)
57
+ end
58
+ end
59
+
60
+ def query(qry=nil)
61
+ if !qry.nil?
62
+ @query = Lycra::Search::Query[qry]
63
+ self
64
+ else
65
+ @query ||= Lycra::Search::Query[send("#{query_method}_query")]
66
+ end
67
+ end
68
+
69
+ def to_query_hash
70
+ {
71
+ query: query.to_query,
72
+ filter: filters.to_query,
73
+ sort: sorter.to_query,
74
+ post_filter: post_filters.to_query,
75
+ aggregations: aggregations.to_query
76
+ }
77
+ end
78
+ alias_method :to_query, :to_query_hash
79
+ alias_method :to_q, :to_query_hash
80
+
81
+ def match_all_query
82
+ {match_all: {}}
83
+ end
84
+
85
+ def multi_match_query
86
+ return if term.nil?
87
+
88
+ {
89
+ multi_match: {
90
+ query: term,
91
+ type: :best_fields,
92
+ fields: fields,
93
+ tie_breaker: 0.5,
94
+ operator: 'and'
95
+ }
96
+ }
97
+ end
98
+
99
+ def match_phrase_prefix_query
100
+ return if term.nil?
101
+
102
+ field_queries = fields.map do |field|
103
+ {match_phrase_prefix: {field.to_s.gsub(/\^\d\Z/, '').to_sym => term}}
104
+ end
105
+
106
+ {or: field_queries}
107
+ end
108
+
109
+ def query_method(meth=false)
110
+ if meth == false
111
+ @query_method ||= :match_all
112
+ else
113
+ @query = nil
114
+ @query_method = meth
115
+ self
116
+ end
117
+ end
118
+
119
+ def models(mdls=false)
120
+ if mdls != false
121
+ @models = mdls.is_a?(Array) ? mdls : [mdls]
122
+ else
123
+ @models ||= self.class.models
124
+ end
125
+ end
126
+
127
+ def fields(flds=false)
128
+ if flds != false
129
+ @fields = flds.is_a?(Array) ? flds : [flds]
130
+ else
131
+ @fields ||= self.class.fields
132
+ end
133
+ end
134
+
135
+ module ClassMethods
136
+ def inherited(base)
137
+ # Make sure we inherit the parent's class-level instance variables whenever we inherit from the class.
138
+ base.send :instance_variable_set, :@models, models.try(:dup)
139
+ base.send :instance_variable_set, :@fields, fields.try(:dup)
140
+ end
141
+
142
+ def search(term=nil, query: nil, filter: nil, post_filter: nil, sort: nil, models: nil, fields: nil, aggregations: nil, &block)
143
+ new(term, query: query, filter: filter, post_filter: post_filter, sort: sort, models: models, fields: fields, aggregations: aggregations, &block)
144
+ end
145
+
146
+ def singleton
147
+ @singleton ||= search
148
+ end
149
+
150
+ def method_missing(meth, *args, &block)
151
+ return search.send(meth, *args, &block) if singleton.respond_to?(meth)
152
+ super
153
+ end
154
+
155
+ def respond_to_missing?(meth, include_private=false)
156
+ singleton.respond_to?(meth, include_private) || super
157
+ end
158
+
159
+ def fields(*fields)
160
+ @fields = fields unless fields.empty?
161
+ @fields ||= []
162
+ end
163
+
164
+ def models(*models)
165
+ @models = models unless models.empty?
166
+ @models ||= []
167
+ end
168
+ end
169
+ end
170
+ end
data/lib/lycra/version.rb CHANGED
@@ -2,7 +2,7 @@ module Lycra
2
2
  module Version
3
3
  MAJOR = '0'
4
4
  MINOR = '0'
5
- PATCH = '1'
5
+ PATCH = '2'
6
6
  VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
 
8
8
  class << self
data/lib/lycra.rb CHANGED
@@ -1,15 +1,41 @@
1
+ require 'logger'
1
2
  require 'canfig'
2
- require 'lycra/railtie' if defined?(Rails)
3
+ require 'elasticsearch/model'
4
+ require 'lycra/model'
5
+ require 'lycra/search'
6
+ require 'lycra/engine' if defined?(Rails)
3
7
 
4
8
  module Lycra
5
9
  include Canfig::Module
6
10
 
7
11
  configure do |config|
8
- config.elastic_host = nil # the elasticsearch host to use
9
- config.logger = nil # defaults to STDOUT but will use Rails.logger in a rails environment
12
+ config.elasticsearch_host = ENV['ELASTICSEARCH_HOST'] || 'localhost' # elasticsearch host to use when connecting, defaults to ENV var if set or falls back to localhost
13
+ config.elasticsearch_port = ENV['ELASTICSEARCH_PORT'] || 9200 # elasticsearch port to use when connecting, defaults to ENV var if set or falls back to 9200
14
+ config.elasticsearch_url = ENV['ELASTICSEARCH_URL'] # elasticsearch URL to use when connecting (i.e. 'https://localhost:9200'), this will override host/port if set
15
+ config.page_size = 50 # default number of results to return per-page when searching an index
16
+ config.index_prefix = nil # a prefix to use for index names (i.e. 'my-app' prefix and 'people' index becomes 'my-app-people')
17
+ config.log = false # whether or not the elasticsearch client should perform standard logging
18
+ config.logger = nil # logger use for standard elasticsearch logging, defaults to STDOUT but will use Rails.logger in a rails environment (via Lycra::Engine)
19
+ config.trace = false # whether or not the elasticsearch client should log request/response traces
20
+ config.tracer = nil # logger used when tracing request/response data
21
+
22
+ def elasticsearch_url
23
+ @state[:elasticsearch_url] || "#{self.elasticsearch_host}:#{self.elasticsearch_port}"
24
+ end
25
+
26
+ def logger
27
+ @logger ||= (@state[:logger] || Logger.new(STDOUT))
28
+ end
10
29
  end
11
30
 
12
- def self.logger
13
- configuration.logger || Logger.new(STDOUT)
31
+ def self.client
32
+ @client ||= Elasticsearch::Client.new(
33
+ host: configuration.elasticsearch_url,
34
+ log: configuration.log,
35
+ logger: configuration.logger,
36
+ trace: configuration.trace,
37
+ tracer: configuration.tracer
38
+ )
14
39
  end
40
+
15
41
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Lycra do
4
+ describe '.logger' do
5
+ context 'when configured with a custom logger' do
6
+ let(:logger) do
7
+ Dir.mktmpdir do |dir|
8
+ Logger.new(File.open(File.join(dir, 'lycra.log'), 'w'))
9
+ end
10
+ end
11
+
12
+ before do
13
+ Lycra.configuration.configure(logger: logger)
14
+ Lycra.configuration.instance_variable_set(:@logger, nil)
15
+ end
16
+
17
+ it 'uses the custom logger' do
18
+ expect(Lycra.configuration.logger).to eq(logger)
19
+ end
20
+ end
21
+
22
+ context 'with default configuration' do
23
+ before do
24
+ Lycra.configuration.configure(logger: nil)
25
+ Lycra.configuration.instance_variable_set(:@logger, nil)
26
+ end
27
+
28
+ it 'is an instance of Logger' do
29
+ expect(Lycra.configuration.logger).to be_an_instance_of(::Logger)
30
+ end
31
+
32
+ it 'uses STDOUT' do
33
+ expect(Lycra.configuration.logger.instance_variable_get(:@logdev).dev).to eq(STDOUT)
34
+ end
35
+ end
36
+ end
37
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,23 +1,21 @@
1
+ require 'faker'
2
+ require 'factory_girl'
1
3
  require 'lycra'
2
4
  require 'rspec'
3
- #require 'vcr'
4
5
  require 'coveralls'
5
6
  Coveralls.wear!
6
7
 
7
8
  #Dir[File.join(File.dirname(__FILE__), '..', "spec/support/**/*.rb")].each { |f| require f }
9
+ Dir[File.join(File.dirname(__FILE__), '..', "spec/factories/**/*.rb")].each { |f| require f }
8
10
 
9
- #VCR.configure do |config|
10
- # config.cassette_library_dir = "spec/cassettes"
11
- # config.hook_into :webmock
12
- #end
11
+ #LYCRA_ES1_CLIENT = Elasticsearch::Client.new host: 'localhost', port: 9201
12
+ LYCRA_ES2_CLIENT = Elasticsearch::Client.new host: 'localhost', port: 4500
13
+ Elasticsearch::Model.client = LYCRA_ES2_CLIENT
13
14
 
14
15
  RSpec.configure do |config|
15
- #config.before(:suite) do
16
- # ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
17
- # capture_stdout { load "db/schema.rb" }
18
- # load 'support/models.rb'
19
- #end
20
-
16
+ # configure factory_girl syntax methods
17
+ config.include FactoryGirl::Syntax::Methods
18
+
21
19
  # rspec-expectations config goes here. You can use an alternate
22
20
  # assertion/expectation library such as wrong or the stdlib/minitest
23
21
  # assertions if you prefer.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lycra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Rebec
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-24 00:00:00.000000000 Z
11
+ date: 2016-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: canfig
@@ -24,6 +24,62 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: elasticsearch
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.18
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.18
41
+ - !ruby/object:Gem::Dependency
42
+ name: elasticsearch-persistence
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: elasticsearch-model
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: elasticsearch-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
27
83
  - !ruby/object:Gem::Dependency
28
84
  name: rake
29
85
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +94,20 @@ dependencies:
38
94
  - - ">="
39
95
  - !ruby/object:Gem::Version
40
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
41
111
  - !ruby/object:Gem::Dependency
42
112
  name: rspec
43
113
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +122,34 @@ dependencies:
52
122
  - - ">="
53
123
  - !ruby/object:Gem::Version
54
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: factory_girl
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: faker
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 1.6.6
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 1.6.6
55
153
  description: Open source business intelligence based on elasticsearch queries, inspired
56
154
  by https://github.com/ankane/blazer
57
155
  email:
@@ -61,8 +159,19 @@ extensions: []
61
159
  extra_rdoc_files: []
62
160
  files:
63
161
  - lib/lycra.rb
64
- - lib/lycra/railtie.rb
162
+ - lib/lycra/engine.rb
163
+ - lib/lycra/errors.rb
164
+ - lib/lycra/model.rb
165
+ - lib/lycra/search.rb
166
+ - lib/lycra/search/aggregations.rb
167
+ - lib/lycra/search/enumerable.rb
168
+ - lib/lycra/search/filters.rb
169
+ - lib/lycra/search/pagination.rb
170
+ - lib/lycra/search/query.rb
171
+ - lib/lycra/search/scoping.rb
172
+ - lib/lycra/search/sort.rb
65
173
  - lib/lycra/version.rb
174
+ - spec/lycra_spec.rb
66
175
  - spec/spec_helper.rb
67
176
  homepage: http://github.com/markrebec/lycra
68
177
  licenses: []
@@ -88,4 +197,6 @@ signing_key:
88
197
  specification_version: 4
89
198
  summary: Business intelligence based on elasticsearch queries
90
199
  test_files:
200
+ - spec/lycra_spec.rb
91
201
  - spec/spec_helper.rb
202
+ has_rdoc:
data/lib/lycra/railtie.rb DELETED
@@ -1,9 +0,0 @@
1
- module Lycra
2
- class Railtie < Rails::Railtie
3
- initializer "lycra.configure_rails_logger" do
4
- Lycra.configure do |config|
5
- config.logger = Rails.logger
6
- end
7
- end
8
- end
9
- end