summon 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.specification +58 -0
  2. data/History.txt +4 -0
  3. data/Manifest.txt +52 -0
  4. data/PostInstall.txt +4 -0
  5. data/README.rdoc +77 -0
  6. data/Rakefile +25 -0
  7. data/bin/summon +10 -0
  8. data/bin/summonh +19 -0
  9. data/ispec/integration_spec.rb +61 -0
  10. data/lib/summon.rb +41 -0
  11. data/lib/summon/cli.rb +136 -0
  12. data/lib/summon/log.rb +40 -0
  13. data/lib/summon/schema.rb +109 -0
  14. data/lib/summon/schema/availability.rb +14 -0
  15. data/lib/summon/schema/citation.rb +11 -0
  16. data/lib/summon/schema/date.rb +23 -0
  17. data/lib/summon/schema/document.rb +84 -0
  18. data/lib/summon/schema/error.rb +4 -0
  19. data/lib/summon/schema/facet.rb +51 -0
  20. data/lib/summon/schema/query.rb +96 -0
  21. data/lib/summon/schema/range.rb +52 -0
  22. data/lib/summon/schema/search.rb +37 -0
  23. data/lib/summon/schema/suggestion.rb +5 -0
  24. data/lib/summon/service.rb +44 -0
  25. data/lib/summon/transport.rb +13 -0
  26. data/lib/summon/transport/canned.json +2327 -0
  27. data/lib/summon/transport/canned.rb +9 -0
  28. data/lib/summon/transport/errors.rb +12 -0
  29. data/lib/summon/transport/headers.rb +55 -0
  30. data/lib/summon/transport/http.rb +114 -0
  31. data/lib/summon/transport/qstring.rb +49 -0
  32. data/script/console +10 -0
  33. data/script/destroy +14 -0
  34. data/script/generate +14 -0
  35. data/spec/spec.opts +1 -0
  36. data/spec/spec_helper.rb +19 -0
  37. data/spec/summon/log_spec.rb +28 -0
  38. data/spec/summon/schema/availability_spec.rb +31 -0
  39. data/spec/summon/schema/citation_spec.rb +34 -0
  40. data/spec/summon/schema/date_spec.rb +12 -0
  41. data/spec/summon/schema/document_spec.rb +235 -0
  42. data/spec/summon/schema/facet_spec.rb +115 -0
  43. data/spec/summon/schema/query_spec.rb +163 -0
  44. data/spec/summon/schema/range_spec.rb +45 -0
  45. data/spec/summon/schema/search_spec.rb +62 -0
  46. data/spec/summon/schema_spec.rb +143 -0
  47. data/spec/summon/service_spec.rb +18 -0
  48. data/spec/summon/transport/headers_spec.rb +47 -0
  49. data/spec/summon/transport/http_spec.rb +29 -0
  50. data/spec/summon/transport/qstring_spec.rb +24 -0
  51. data/spec/summon_spec.rb +48 -0
  52. data/summon.gemspec +41 -0
  53. metadata +145 -0
data/lib/summon/log.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'logger'
2
+
3
+ module Summon
4
+ class Log
5
+
6
+ attr_reader :impl
7
+
8
+ def initialize(spec = nil)
9
+ @impl = create spec
10
+ end
11
+
12
+ def method_missing(name, *args, &block)
13
+ @impl.respond_to?(name) ? @impl.send(name, *args, &block) : super(name, *args, &block)
14
+ end
15
+
16
+ def respond_to?(name)
17
+ @impl.respond_to?(name) || super(name)
18
+ end
19
+
20
+ private
21
+
22
+ def create(spec)
23
+ case spec
24
+ when nil
25
+ Logger.new($stderr).tap do |this|
26
+ this.level = Logger::WARN
27
+ end
28
+ when Hash
29
+ level = spec[:level] || "warn"
30
+ init = spec[:initialize] || [$stderr]
31
+ Logger.new(*init).tap do |this|
32
+ this.level = Logger.const_get(level.to_s.upcase)
33
+ end
34
+ else
35
+ spec
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,109 @@
1
+
2
+ module Summon
3
+ class Schema
4
+ def self.inherited(mod)
5
+ class << mod
6
+ include Summon::Schema::Initializer
7
+ include Summon::Schema::ClassMethods
8
+ end
9
+ mod.module_eval do
10
+ include Summon::Schema::InstanceMethods
11
+ end
12
+ mod.summon!
13
+ end
14
+
15
+ module Initializer
16
+ def new(values = {})
17
+ dup = {}
18
+ for k, v in values
19
+ dup[k.to_s] = v
20
+ end
21
+ instance = allocate
22
+ instance.instance_eval do
23
+ @src = values
24
+ end
25
+ for attribute in @attrs
26
+ instance.instance_variable_set("@#{attribute.name}", attribute.get(dup))
27
+ end
28
+ instance
29
+ end
30
+ end
31
+
32
+ module ClassMethods
33
+
34
+ def attr(name, options = {})
35
+ if name.to_s =~ /^(.*)\?$/
36
+ name = $1
37
+ options[:boolean] = true
38
+ end
39
+ symbol = name.to_sym
40
+ @attrs << ::Summon::Schema::Attr.new(symbol, options)
41
+ define_method(name) do |*args|
42
+ self.instance_variable_get("@#{name}")
43
+ end
44
+ if options[:boolean]
45
+ define_method("#{name}?") do
46
+ send(name)
47
+ end
48
+ end
49
+ end
50
+
51
+ def attrs
52
+ @attrs
53
+ end
54
+
55
+ def summon!
56
+ @attrs = []
57
+ attr_reader :src
58
+ end
59
+ end
60
+
61
+ module InstanceMethods
62
+ def to_json(*a)
63
+ self.class.attrs.inject({}) do |json, attr|
64
+ json.merge attr.name => self.send(attr.name)
65
+ end.to_json(*a)
66
+ end
67
+ end
68
+
69
+ class Attr
70
+ attr_reader :name
71
+ def initialize(name, options)
72
+ @name = name
73
+ @boolean = options[:boolean]
74
+ @camel_name = camelize(name.to_s)
75
+ @pascal_name = @camel_name.gsub(/^\w/) {|first| first.upcase}
76
+ @transform = options[:transform]
77
+ @json_name = options[:json_name].to_s if options[:json_name]
78
+ @json_name = "is#{@pascal_name}" if @boolean unless @json_name
79
+ @single = options[:single].nil? ? !(name.to_s.downcase =~ /s$/) : options[:single]
80
+ end
81
+
82
+ def get(json)
83
+ raw = json[@json_name || @camel_name]
84
+ raw = json[@pascal_name] if raw.nil?
85
+ if raw.nil?
86
+ @single ? nil : []
87
+ else
88
+ raw = @single && raw.kind_of?(Array) ? raw.first : raw
89
+ transform(raw) || raw
90
+ end
91
+ end
92
+
93
+ def camelize(str)
94
+ str.gsub /(\w)_(\w)/ do
95
+ "#{$1}#{$2.upcase}"
96
+ end
97
+ end
98
+
99
+ def transform(raw)
100
+ if @transform
101
+ ctor = proc do |h|
102
+ ::Summon.const_get(@transform).new(h)
103
+ end
104
+ raw.kind_of?(Array) ? raw.map(&ctor) : ctor.call(raw)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,14 @@
1
+ class Summon::Availability < Summon::Schema
2
+ attr :token
3
+ attr :status
4
+ attr :status_message
5
+ attr :location
6
+ attr :location_string
7
+ attr :call_number
8
+
9
+ def self.parse_results(results)
10
+ results["Result"]["RecordSummary"].map do |record|
11
+ new(record["Record"].merge(:token => record["ID"]))
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ class Summon::Citation < Summon::Schema
2
+ attr :name
3
+ attr :label
4
+ attr :short_name
5
+ attr :caption
6
+ attr :text
7
+
8
+ def self.parse_results(results)
9
+ results["Results"]["Citations"]["Citation"].map {|result| new(result) }
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+
2
+ class Summon::Date < Summon::Schema
3
+ attr :day
4
+ attr :month
5
+ attr :text
6
+ attr :year
7
+
8
+ def day
9
+ @day.to_i if @day
10
+ end
11
+
12
+ def month
13
+ @month.to_i if @month
14
+ end
15
+
16
+ def year
17
+ @year.to_i if @year
18
+ end
19
+
20
+ def to_s(options = {})
21
+ "Date: #{text}"
22
+ end
23
+ end
@@ -0,0 +1,84 @@
1
+
2
+ class Summon::Document < Summon::Schema
3
+ attr :id, :json_name => "ID"
4
+ attr :title
5
+ attr :subtitle
6
+ attr :publication_title
7
+ attr :publication_series_title
8
+ attr :content_type
9
+
10
+ attr :authors, :json_name => "Author"
11
+ attr :publishers, :json_name => "Publisher"
12
+ attr :volume
13
+ attr :issue
14
+ attr :start_page
15
+ attr :end_page
16
+ attr :page_count
17
+ attr :publication_date, :json_name => "PublicationDate_xml", :transform => :Date
18
+
19
+ attr :dissertation_advisor
20
+ attr :dissertation_category
21
+ attr :dissertation_degree
22
+ attr :dissertation_degree_date
23
+ attr :dissertation_degree_date_decade
24
+ attr :dissertation_degree_date_century
25
+ attr :dissertation_degree_date_year
26
+ attr :dissertation_school
27
+
28
+ attr :library
29
+ attr :call_number, :json_name => "LCCallNum"
30
+ attr :doi, :json_name => "DOI"
31
+ attr :isbns, :json_name => "ISBN"
32
+ attr :issns, :json_name => "ISSN"
33
+ attr :patent_number
34
+
35
+
36
+ attr :subject_terms
37
+ attr :genres, :json_name => "Genre"
38
+ attr :languages, :json_name => "Language"
39
+
40
+ attr :snippet #highlight
41
+ attr :abstract
42
+ attr :fulltext, :boolean => true, :json_name => "hasFullText"
43
+ attr :url
44
+ attr :open_url
45
+ attr :subject_terms
46
+
47
+ attr :thumbnail_small, :json_name => "Thumbnail-s"
48
+ attr :thumbnail_medium, :json_name => "Thumbnail-m"
49
+ attr :thumbnail_large, :json_name => "Thumbnail-l"
50
+ attr :availability_token
51
+
52
+
53
+ def isbn
54
+ @isbns.first
55
+ end
56
+
57
+ def pages?
58
+ @start_page || @page_count
59
+ end
60
+
61
+ def publication_date
62
+ @publication_date || Summon::Date.new({})
63
+ end
64
+
65
+ def publisher
66
+ @publishers.first
67
+ end
68
+
69
+ def authors
70
+ @authors.map {|n| Summon::Author.new(n)}
71
+ end
72
+
73
+ def to_s(options = {})
74
+ "Title: #{title}"
75
+ end
76
+ end
77
+
78
+
79
+ class Summon::Author < Struct.new(:name)
80
+ def name(*args)
81
+ super()
82
+ end
83
+ end
84
+
@@ -0,0 +1,4 @@
1
+ class Summon::Error < Summon::Schema
2
+ attr :suggestion, :transform => :Suggestion
3
+ attr :message
4
+ end
@@ -0,0 +1,51 @@
1
+
2
+ class Summon::Facet < Summon::Schema
3
+ attr :page_size
4
+ attr :display_name
5
+ attr :field_name
6
+ attr :combine_mode
7
+ attr :page_number
8
+ attr :counts, :transform => :FacetCount
9
+ attr :remove_command
10
+ attr :remove_value_filters_command
11
+
12
+ def to_s
13
+ "Facet(#{display_name}, #{field_name})"
14
+ end
15
+
16
+ def range?
17
+ false
18
+ end
19
+
20
+ def empty?
21
+ @counts.empty?
22
+ end
23
+ end
24
+
25
+ class Summon::FacetCount < Summon::Schema
26
+ attr :value
27
+ attr :count
28
+ attr :negated?
29
+ attr :applied?
30
+ attr :further_limiting?
31
+ attr :apply_command
32
+ attr :apply_negated_command
33
+ attr :remove_command
34
+
35
+ def escaped_value
36
+ Summon.escape(@value)
37
+ end
38
+
39
+ def excluded?
40
+ negated?
41
+ end
42
+
43
+ def included?
44
+ applied? && !excluded?
45
+ end
46
+
47
+ def abs_value
48
+ value.sub /^-/, ''
49
+ end
50
+
51
+ end
@@ -0,0 +1,96 @@
1
+ class Summon::Query < Summon::Schema
2
+
3
+ attr :page_number
4
+ attr :page_size
5
+ attr :search_terms
6
+ attr :query_string
7
+ attr :facet_value_filters, :transform => :FacetValueFilter
8
+ attr :facet_value_group_filters, :transform => :FacetValueGroupFilter
9
+ attr :text_queries
10
+ attr :text_filters
11
+ attr :range_filters, :transform => :RangeFilter
12
+ attr :facet_fields
13
+ attr :sorts, :transform => :Sort, :json_name => "sort"
14
+ attr :params
15
+ attr :holdings_only_enabled?
16
+
17
+ def sort
18
+ @sorts.first
19
+ end
20
+
21
+ def date_min
22
+ date_filter do |f|
23
+ val = f.range.min_value
24
+ return val == "*" ? nil : val.to_i
25
+ end
26
+ end
27
+
28
+ def date_max
29
+ date_filter do |f|
30
+ val = f.range.max_value
31
+ return val == "*" ? nil : val.to_i
32
+ end
33
+ end
34
+
35
+ def date_filter
36
+ range_filters.find {|f| f.field_name == "PublicationDate"}.tap do |this|
37
+ yield this if this && block_given?
38
+ end
39
+ end
40
+
41
+ def to_hash
42
+ return {} if query_string.nil? || query_string == ""
43
+ params = query_string.split("&").inject({}) do |params, param|
44
+ name, value = param.split("=")
45
+ name = CGI.unescape(name)
46
+ value = CGI.unescape(value)
47
+ params.tap do
48
+ case params[name]
49
+ when nil
50
+ params[name] = value
51
+ when String
52
+ params[name] = [params[name], value]
53
+ else
54
+ params[name] << value
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ class Summon::Sort < Summon::Schema
62
+ attr :field_name
63
+ attr :sort_order
64
+ end
65
+
66
+ class Summon::FacetValueFilter < Summon::Schema
67
+ attr :negated?
68
+ attr :value
69
+ attr :field_name
70
+ attr :remove_command
71
+ attr :negate_command
72
+ end
73
+
74
+ class Summon::FacetValueGroupFilter < Summon::Schema
75
+ attr :combine_mode
76
+ attr :tag
77
+ attr :field_name
78
+ attr :remove_command
79
+ attr :values, :transform => :FacetValueGroupFilterValue
80
+ end
81
+
82
+ class Summon::FacetValueGroupFilterValue < Summon::Schema
83
+ attr :value
84
+ attr :remove_command
85
+ end
86
+
87
+ class Summon::RangeFilter < Summon::Schema
88
+ attr :field_name
89
+ attr :range, :transform => :Range
90
+ attr :remove_command
91
+ end
92
+
93
+ class Summon::Range < Summon::Schema
94
+ attr :min_value
95
+ attr :max_value
96
+ end
@@ -0,0 +1,52 @@
1
+
2
+ class Summon::RangeFacet < Summon::Schema
3
+ attr :display_name
4
+ attr :field_name
5
+ attr :remove_command
6
+ attr :counts, :transform => :RangeCount
7
+
8
+ def clear_filters_command
9
+ "removeRangeFilter(#{field_name})"
10
+ end
11
+
12
+ def empty?
13
+ false
14
+ end
15
+
16
+ # #COMPATIBILITY
17
+ #
18
+ # alias_method :name, :display_name
19
+ # alias_method :label, :display_name
20
+ # alias_method :facets, :counts
21
+ # alias_method :ranges, :counts
22
+
23
+ end
24
+
25
+ class Summon::RangeCount < Summon::Schema
26
+ attr :count
27
+ attr :applied?
28
+ attr :apply_command
29
+ attr :range
30
+
31
+ def min
32
+ @range["minValue"]
33
+ end
34
+
35
+ def max
36
+ @range["maxValue"]
37
+ end
38
+
39
+ def abs_value
40
+ ""
41
+ end
42
+
43
+ def apply_negated_command
44
+ ""
45
+ end
46
+
47
+ alias_method :included?, :applied?
48
+
49
+ def excluded?
50
+ false
51
+ end
52
+ end