primedia-endeca 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.0 / 2009-01-20
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/Manifest.txt ADDED
@@ -0,0 +1,31 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ endeca.gemspec
6
+ example/benchmark.rb
7
+ example/listing.rb
8
+ lib/class_to_proc.rb
9
+ lib/core_ext.rb
10
+ lib/endeca.rb
11
+ lib/endeca/dimension.rb
12
+ lib/endeca/document.rb
13
+ lib/endeca/document_collection.rb
14
+ lib/endeca/map.rb
15
+ lib/endeca/readers.rb
16
+ lib/endeca/refinement.rb
17
+ lib/endeca/request.rb
18
+ lib/endeca/transformer.rb
19
+ spec/core_ext_spec.rb
20
+ spec/endeca/dimension_spec.rb
21
+ spec/endeca/document_collection_spec.rb
22
+ spec/endeca/document_spec.rb
23
+ spec/endeca/map_spec.rb
24
+ spec/endeca/readers_spec.rb
25
+ spec/endeca/refinement_spec.rb
26
+ spec/endeca/request_spec.rb
27
+ spec/endeca/transformer_spec.rb
28
+ spec/endeca_spec.rb
29
+ spec/rcov.opts
30
+ spec/spec.opts
31
+ spec/spec_helper.rb
data/README.rdoc ADDED
@@ -0,0 +1,60 @@
1
+ endeca
2
+ by Rein Henrichs and Andy Stone
3
+
4
+ == DESCRIPTION:
5
+
6
+ An Endeca client library for Ruby.
7
+
8
+ == FEATURES/PROBLEMS:
9
+
10
+ == SYNOPSIS:
11
+ class Listing < Endeca::Document
12
+ path 'http://endeca.example.com/api'
13
+
14
+ map :id => 'R'
15
+ map(:expand_refinements => :expand_all_dims).into(:M)
16
+
17
+ float_reader \
18
+ :latitude,
19
+ :longitude,
20
+
21
+ integer_reader :endeca_id
22
+
23
+ boolean_reader :isawesome => :awesome?
24
+ end
25
+
26
+ Listing.find(1234).awesome? # => true
27
+ Listing.find(:all, :per_page => 10).size # => 10
28
+
29
+ == REQUIREMENTS:
30
+
31
+ * FakeWeb (for running tests)
32
+
33
+ == INSTALL:
34
+
35
+ sudo gem install primedia-endeca --source=http://gems.github.com
36
+
37
+ == LICENSE:
38
+
39
+ (The MIT License)
40
+
41
+ Copyright (c) 2008 PRIMEDIA Inc.
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining
44
+ a copy of this software and associated documentation files (the
45
+ 'Software'), to deal in the Software without restriction, including
46
+ without limitation the rights to use, copy, modify, merge, publish,
47
+ distribute, sublicense, and/or sell copies of the Software, and to
48
+ permit persons to whom the Software is furnished to do so, subject to
49
+ the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be
52
+ included in all copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
55
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
58
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
59
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
60
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'endeca'
18
+
19
+ task :default => 'rcov'
20
+
21
+ desc "Simple benchmarking"
22
+ task :benchmark do
23
+ sh('ruby example/benchmark.rb')
24
+ end
25
+ task :bm => :benchmark
26
+
27
+ desc "Flog your code for Justice!"
28
+ task :flog do
29
+ sh('flog lib/**/*.rb')
30
+ end
31
+
32
+ desc "Run all specs and rcov in a non-sucky way"
33
+ Spec::Rake::SpecTask.new(:rcov) do |t|
34
+ t.spec_opts = IO.readlines("spec/spec.opts").map {|l| l.chomp.split " "}.flatten
35
+ t.spec_files = FileList['spec/**/*_spec.rb']
36
+ t.rcov = true
37
+ t.rcov_opts = IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
38
+ end
39
+
40
+ PROJ.name = 'endeca'
41
+ PROJ.authors = ['Rein Henrichs', 'Andy Stone']
42
+ PROJ.email = ''
43
+ PROJ.url = 'http://github.com/primedia/endeca-ruby'
44
+ PROJ.version = Endeca::VERSION
45
+ PROJ.rubyforge.name = 'endeca-ruby'
46
+ PROJ.readme_file = "README.rdoc"
47
+
48
+ # EOF
@@ -0,0 +1,13 @@
1
+ require 'benchmark'
2
+
3
+ $:.unshift(File.expand_path(File.dirname(__FILE__)))
4
+ require 'lib/endeca'
5
+ require 'listing'
6
+
7
+ RUNS = 10
8
+ Benchmark.bmbm do |results|
9
+ results.report('Full Request') {RUNS.times{Listing.all}}
10
+ results.report('Parse JSON') {RUNS.times{Endeca::Request.perform(Listing.get_path,'')}}
11
+ results.report('Get Net Response') {RUNS.times{Endeca::Request.new(Listing.get_path,'').send(:get_response)}}
12
+ end
13
+
@@ -0,0 +1,36 @@
1
+ require 'lib/endeca'
2
+ class Listing < Endeca::Document
3
+ path 'http://192.168.3.218:8888/bridge/JSONControllerServlet.do'
4
+
5
+ reader \
6
+ :address,
7
+ :contact,
8
+ :description,
9
+ :header,
10
+ :phone
11
+
12
+ integer_reader \
13
+ 'RecordSpec' => :listing_id
14
+
15
+ float_reader \
16
+ :longitude,
17
+ :latitude
18
+
19
+ decimal_reader :rent => :price
20
+
21
+ boolean_reader :showemail => :show_email?
22
+
23
+ reader(:rh_url => :details_url) {|url| "/{url}"}
24
+
25
+ add_reader(:caret_delimited_reader) {|string| string.split('^+^')}
26
+
27
+ caret_delimited_reader \
28
+ :thumbnails,
29
+ :graphicurl => :graphic_urls
30
+
31
+ def coordinates; [latitude, longitude] end
32
+ def image_url; (graphic_urls || thumbnails).first rescue nil end
33
+
34
+ dim_reader :zip, :bathrooms, :bedrooms
35
+
36
+ end
@@ -0,0 +1,5 @@
1
+ module ClassToProc
2
+ def to_proc
3
+ proc(&method(:new))
4
+ end
5
+ end
data/lib/core_ext.rb ADDED
@@ -0,0 +1,73 @@
1
+ class Array
2
+ def to_params
3
+ join('&').to_params
4
+ end
5
+ end
6
+
7
+ class Class
8
+ def inherited_property(accessor, default = nil)
9
+ instance_eval <<-RUBY, __FILE__, __LINE__ + 1
10
+ @#{accessor} = default
11
+
12
+ def set_#{accessor}(value)
13
+ @#{accessor} = value
14
+ end
15
+ alias #{accessor} set_#{accessor}
16
+
17
+ def get_#{accessor}
18
+ return @#{accessor} if instance_variable_defined?(:@#{accessor})
19
+ superclass.send(:#{accessor})
20
+ end
21
+ RUBY
22
+
23
+ # @path = default
24
+ #
25
+ # def set_path(value)
26
+ # @path = value
27
+ # end
28
+ # alias_method path, set_path
29
+
30
+ # def get_path
31
+ # return @path if instance_variable_defined?(:path)
32
+ # superclass.send(:path)
33
+ # end
34
+ end
35
+
36
+ def inherited_accessor(accessor, default = nil)
37
+ instance_eval <<-RUBY, __FILE__, __LINE__ + 1
38
+ class << self; attr_writer :#{accessor}; end
39
+ @#{accessor} = default
40
+
41
+ def #{accessor}
42
+ return @#{accessor} if instance_variable_defined?(:@#{accessor})
43
+ superclass.send(:#{accessor})
44
+ end
45
+ RUBY
46
+ end
47
+ end
48
+
49
+ class Hash
50
+ def to_params
51
+ map { |k, v|
52
+ if v.instance_of?(Hash)
53
+ v.map { |sk, sv|
54
+ "#{k}[#{sk}]=#{sv}"
55
+ }.join('&')
56
+ else
57
+ "#{k}=#{v}"
58
+ end
59
+ }.join('&').to_params
60
+ end
61
+ end
62
+
63
+ class NilClass
64
+ def to_params
65
+ ''
66
+ end
67
+ end
68
+
69
+ class String
70
+ def to_params
71
+ URI.escape(self)
72
+ end
73
+ end
data/lib/endeca.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'logger'
5
+
6
+ $:.unshift(File.dirname(__FILE__))
7
+ require 'core_ext'
8
+ require 'class_to_proc'
9
+ require 'endeca/readers'
10
+ require 'endeca/map'
11
+ require 'endeca/transformer'
12
+ require 'endeca/dimension'
13
+ require 'endeca/refinement'
14
+ require 'endeca/request'
15
+ require 'endeca/document_collection'
16
+ require 'endeca/document'
17
+
18
+ module Endeca
19
+
20
+ # :stopdoc:
21
+ VERSION = '0.9.0'
22
+ # :startdoc:
23
+
24
+ # Returns the version string for the library.
25
+ #
26
+ def self.version
27
+ VERSION
28
+ end
29
+
30
+ # Set Endeca.debug = true to turn on query logging
31
+ class << self
32
+ attr_accessor :debug
33
+ attr_accessor :logger
34
+ end
35
+
36
+ self.debug = false
37
+ self.logger = Logger.new(STDOUT)
38
+ end
@@ -0,0 +1,30 @@
1
+ module Endeca
2
+ class Dimension
3
+ include Comparable
4
+ extend ClassToProc
5
+ extend Readers
6
+
7
+ attr_reader :raw
8
+ def initialize(raw={})
9
+ @raw=raw
10
+ end
11
+ alias_method :attributes, :raw
12
+
13
+ reader "DimValueName" => :name
14
+ reader "PivotLink" => :to_params
15
+
16
+ integer_reader "DimValueID" => :id
17
+
18
+ def inspect
19
+ "#<#{self.class}=0x#{self.object_id.to_s(16)} id=#{id} name=#{name.inspect}>"
20
+ end
21
+
22
+ def ==(other)
23
+ id == other.id
24
+ end
25
+
26
+ def <=>(other)
27
+ name <=> other.name
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,109 @@
1
+ module Endeca
2
+ # Endeca Documents provide accessors for document properties
3
+ # returned by an Endeca query. Interesting Document properties must be
4
+ # declared with reader to be accessible on the object.
5
+ #
6
+ # The +reader+ declaration provided by Readers can also handle basic data transformations (i.e.
7
+ # typecasting) and a few basic examples are provided (i.e. +integer_reader+).
8
+ class Document
9
+ extend ClassToProc
10
+ extend Readers
11
+ extend Transformer
12
+
13
+ inherited_accessor :mappings, {}
14
+ inherited_property :path
15
+ inherited_property :default_params, {}
16
+
17
+ reader :id
18
+
19
+ attr_reader :raw, :properties
20
+ def initialize(record_raw=nil)
21
+ @raw = record_raw || {}
22
+ @properties = @raw['Properties'] || {}
23
+ end
24
+
25
+ alias_method :attributes, :properties
26
+
27
+ def ==(other)
28
+ id == other.id
29
+ end
30
+
31
+ def inspect
32
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}>"
33
+ end
34
+
35
+ # Returns the collection of Endeca::Dimension for the given Document
36
+ def dimensions
37
+ return @dimensions if @dimensions
38
+ @dimensions = {}
39
+ (raw['Dimensions'] || {}).each do |name, value|
40
+ @dimensions[name] = Dimension.new(value)
41
+ end
42
+ @dimensions
43
+ end
44
+
45
+ # Find operates with three distinct retrieval approaches:
46
+ #
47
+ # * Find by id - This is a specific id (1) or id string ("1")
48
+ # * Find first - This will return the first record matching the query options
49
+ # used
50
+ # * Find all - This will return a collection of Documents matching the
51
+ # query options. This is the default behavior of find if only query options
52
+ # are passed.
53
+ #
54
+ # ==== Parameters
55
+ #
56
+ # Find accepts a query options hash. These options are either passed
57
+ # directly to Endeca or mapped (by use of +map+) to new parameters that are
58
+ # passed to Endeca.
59
+ #
60
+ # ==== Examples
61
+ #
62
+ # # find by id
63
+ # Listing.find(1) # returns the Document for ID = 1
64
+ # Listing.find('1') # returns the Document for ID = 1
65
+ #
66
+ # # find all
67
+ # Listing.find(:all) # returns a collection of Documents
68
+ # Listing.find(:all, :available => true)
69
+ #
70
+ # # find first
71
+ # Listing.find(:first) # Returns the first Document for the query
72
+ # Listing.find(:first, :available => true)
73
+ def self.find(what, query_options={})
74
+ case what
75
+ when Integer, /^\d+$/
76
+ by_id(what, query_options)
77
+ when :first
78
+ first(query_options)
79
+ when :all
80
+ all(query_options)
81
+ else
82
+ all(what)
83
+ end
84
+ end
85
+
86
+ # Returns the first Document matching the query options.
87
+ def self.first(query_options={})
88
+ records = request(query_options)['Records']
89
+ records && new(records.first)
90
+ end
91
+
92
+ # Returns all Documents matching the query options.
93
+ def self.all(query_options={})
94
+ DocumentCollection.new(request(query_options), self)
95
+ end
96
+
97
+ # Returns a Document by id
98
+ def self.by_id(id, query_options={})
99
+ first(query_options.merge(:id => id))
100
+ end
101
+
102
+ private
103
+
104
+ def self.request(query_options)
105
+ query_options = transform_query_options(query_options.merge(get_default_params))
106
+ Endeca::Request.perform(get_path, query_options)
107
+ end
108
+ end
109
+ end