drawbridge 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Michael Hoitomt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Drawbridge
2
+
3
+ [![Code Climate](https://codeclimate.com/repos/51d44e1c13d637371b0595e6/badges/f566eeb7ce85f64716ec/gpa.png)](https://codeclimate.com/repos/51d44e1c13d637371b0595e6/feed)
4
+
5
+ It draws the bridge between Endeca JSON bridge and IDG sites.
6
+
7
+ Sometimes it's up, sometimes it's down.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'drawbridge'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install drawbridge
22
+
23
+ ## Setup
24
+
25
+ To use:
26
+
27
+ ```ruby
28
+ require 'drawbridge'
29
+
30
+ Drawbridge.setup do |config|
31
+ config.bridge_url = "http://example.com:8080"
32
+ config.bridge_path = "BridgeAPIService_apt64/servlet/bridgeapi.json"
33
+ # e.g. ENDECA_DEBUG=true rackup
34
+ config.endeca_debug = ENV.fetch('ENDECA_DEBUG') { false }
35
+ # optional, default is 5
36
+ config.timeout = 5
37
+ # optional, default is to change ' into ' before JSON is parsed
38
+ config.skip_single_quote_encoding = true
39
+ end
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ [Endeca documentation here](https://github.com/primedia/idg/wiki/Endeca)
45
+
46
+ ## Contributing
47
+
48
+ 1. Fork it
49
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
50
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
51
+ 4. Push to the branch (`git push origin my-new-feature`)
52
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+ task :spec => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'spec'
9
+ t.test_files = FileList['spec/*_spec.rb']
10
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'drawbridge/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "drawbridge"
8
+ gem.version = Drawbridge::VERSION
9
+ gem.authors = ["Michael Hoitomt"]
10
+ gem.email = ["mhoitomt@primedia.com"]
11
+ gem.description = %q{Papi's Wife}
12
+ gem.summary = %q{Papi's Replacement}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency('turn', '~> 0.8.3')
21
+ gem.add_development_dependency('mocha', '~> 0.13.0')
22
+ gem.add_development_dependency('rake')
23
+
24
+ gem.add_dependency('curb', '~> 0.8.4')
25
+ gem.add_dependency('oj', '~> 2.0.14')
26
+ gem.add_dependency('activesupport', '>= 3.2.9')
27
+ end
data/lib/drawbridge.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'active_support/core_ext/object/blank'
2
+ require 'drawbridge/version'
3
+ require 'drawbridge/config'
4
+ require 'drawbridge/debug'
5
+ require 'drawbridge/transformer'
6
+ require 'drawbridge/adapter'
7
+ require 'drawbridge/mapper'
8
+ require 'drawbridge/request'
9
+ require 'drawbridge/result'
10
+ require 'drawbridge/refinement_scrubber'
11
+
12
+ module Drawbridge
13
+ end
@@ -0,0 +1,35 @@
1
+ module Drawbridge
2
+ class Adapter
3
+ include Drawbridge::Transformer
4
+
5
+ attr_accessor :mapper
6
+
7
+ def initialize(mapper)
8
+ @mapper = mapper
9
+ end
10
+
11
+ def search_path
12
+ "#{Drawbridge.config.bridge_url}/#{Drawbridge.config.bridge_path}"
13
+ end
14
+
15
+ def build_all_query
16
+ params = {
17
+ select: mapper.fields,
18
+ where: mapper.record_search,
19
+ record_filters: mapper.record_filters,
20
+ root_navigtion: mapper.navigation,
21
+ expand_refinements: mapper.dimensions,
22
+ geo_filter: mapper.geo_filters,
23
+ range_filter: mapper.range_filter,
24
+ rollup: mapper.rollup_key,
25
+ match_mode: mapper.mode,
26
+ aggregate_offset: mapper.aggregate_offset,
27
+ offset: mapper.offset,
28
+ limit: mapper.limit_param,
29
+ order: mapper.sort_key
30
+ }
31
+ transform(params)
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,48 @@
1
+ module Drawbridge
2
+ class Config
3
+ attr_accessor :data
4
+ def initialize(data={})
5
+ @data = {}
6
+ update!(data)
7
+ end
8
+
9
+ def update!(data)
10
+ data.each do |key, value|
11
+ self[key.to_sym] = value
12
+ end
13
+ end
14
+
15
+ def [](key)
16
+ @data[key.to_sym]
17
+ end
18
+
19
+ def []=(key, value)
20
+ @data[key.to_sym] = value
21
+ end
22
+
23
+ def keys
24
+ @data.keys
25
+ end
26
+
27
+ def to_hash
28
+ @data
29
+ end
30
+
31
+ def method_missing(sym, *args)
32
+ if sym.to_s =~ /(.+)=$/
33
+ self[$1] = args.first
34
+ else
35
+ self[sym]
36
+ end
37
+ end
38
+ end
39
+
40
+ class << self
41
+ attr_accessor :config, :data
42
+
43
+ def setup
44
+ self.config ||= Config.new
45
+ yield config
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Drawbridge
3
+ class Debug
4
+
5
+ def self.draw_line
6
+ @draw_line ||= "*"*80
7
+ end
8
+
9
+ # @params prepend_text: Endeca_Params
10
+ # @params debug_value: any object thaat can be inspected
11
+ def self.log(prepend_text, debug_value)
12
+ if Drawbridge.config.endeca_debug
13
+ puts "#{draw_line}\n#{prepend_text}: #{debug_value.inspect}\n#{draw_line}"
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,214 @@
1
+ module Drawbridge
2
+ class Mapper
3
+
4
+
5
+ # Class Level accessor - Makes pretty
6
+ class << self
7
+ def where(params)
8
+ self.new.where(params)
9
+ end
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def where(params)
16
+ params.each do |k, v|
17
+ # regex should handle md5hash, and anything that doesn't have word characters
18
+ unless k[/\W|^\h+$/]
19
+ Mapper.send(:attr_accessor, k)
20
+ instance_variable_set("@#{k}", v)
21
+ end
22
+ end
23
+ self
24
+ end
25
+
26
+ def order_by(sort_string)
27
+ @sort_string = sort_string
28
+ self
29
+ end
30
+
31
+ def sort_args
32
+ return [] unless @sort_string
33
+ sort_string = @sort_string.split(',').join('^+^')
34
+ sort_array = parse_sort(sort_string.gsub('-', '^'))
35
+ sort_array
36
+ end
37
+
38
+ def all
39
+ adapter = Drawbridge::Adapter.new(self)
40
+ query = adapter.build_all_query
41
+ result_params = Request.perform adapter.search_path, query
42
+ Result.new(result_params)
43
+ end
44
+
45
+ def first
46
+ results = all
47
+ results.records.empty? ? nil : results.records.first
48
+ end
49
+
50
+ def default_refinements
51
+ []
52
+ end
53
+
54
+ # N
55
+ def navigation
56
+ (process_refinements(endeca_refinements) + default_refinements).flatten
57
+ end
58
+
59
+ # Ne - placeholder, might make more sense to hard-code in the adapter
60
+ def exposed_refinements
61
+ dimensions
62
+ end
63
+
64
+ # Ntt and Ntk
65
+ def record_search
66
+ record_key_values
67
+ end
68
+
69
+ # Ns
70
+ def sort_key
71
+ combined_sort
72
+ end
73
+
74
+ # Nr
75
+ def record_filters
76
+ []
77
+ end
78
+
79
+ # Nf
80
+ def range_filter
81
+ []
82
+ end
83
+
84
+ # Nf
85
+ def geo_filters
86
+ {}
87
+ end
88
+
89
+ # Nu
90
+ def rollup_key
91
+ ""
92
+ end
93
+
94
+ # No
95
+ def offset
96
+ page_param.to_i * limit_param.to_i
97
+ end
98
+
99
+ # Nao
100
+ def aggregate_offset
101
+ page_param.to_i * limit_param.to_i
102
+ end
103
+
104
+ def page_param
105
+ @page ? @page.to_i - 1 : 0
106
+ end
107
+
108
+ def limit_param
109
+ @limit ||= 20
110
+ @limit.to_i
111
+ end
112
+
113
+ def radius_param
114
+ @radius ||= @rad
115
+ end
116
+
117
+ def combined_sort
118
+ (base_sort + sort_args).flatten.uniq
119
+ end
120
+
121
+ def base_sort
122
+ []
123
+ end
124
+
125
+ def record_key_values
126
+ {}
127
+ end
128
+
129
+ def dimensions
130
+ []
131
+ end
132
+
133
+ def dimensions=(dimension_list)
134
+ dimension_list
135
+ end
136
+
137
+ def fields
138
+ []
139
+ end
140
+
141
+ def fields=(field_list)
142
+ field_list
143
+ end
144
+
145
+ def method_missing(meth)
146
+ nil
147
+ end
148
+
149
+ def name
150
+ ""
151
+ end
152
+
153
+ def mode
154
+ []
155
+ end
156
+
157
+ # converts refinements to int ids if they were base(36) encoded before
158
+ # @params - Array
159
+ # ["4j7"] => ['5875']
160
+ def process_refinements(refinements)
161
+ return [] if refinements.blank?
162
+
163
+ refinements.collect! do |ref|
164
+ ref.to_i(36).to_s
165
+ end
166
+ end
167
+
168
+ def parse_refinements(refinements)
169
+ refinements.collect! do |ref|
170
+ ref.to_s[/^\d+$/] ? ref.to_s : ref.to_i(36).to_s
171
+ end
172
+ end
173
+
174
+ protected
175
+
176
+ def refinements
177
+ @refinements ||= ""
178
+ end
179
+
180
+ def endeca_refinements
181
+ return [] if @refinements.nil?
182
+ split_out_dimension_codes(@refinements.dup) || []
183
+ end
184
+
185
+ def split_out_dimension_codes(refs)
186
+ nodes = refs.split('-').last
187
+ nodes = nodes.split(/\+|\s/) if nodes
188
+ nodes == ['miles'] ? nil : nodes
189
+ end
190
+
191
+ def parse_sort(sort)
192
+ return [] if sort.nil? || sort.empty?
193
+ [].tap do |a|
194
+ aray_sort = sort.split('^+^')
195
+ aray_sort.each do |s|
196
+ key, val = s.split('^')
197
+ a << {key => endeca_sort_value(val)}
198
+ end
199
+ end
200
+ end
201
+
202
+ def endeca_sort_value(value)
203
+ case value
204
+ when "asc"
205
+ return "0"
206
+ when "desc"
207
+ return "1"
208
+ else
209
+ return value
210
+ end
211
+ end
212
+
213
+ end
214
+ end