summon 1.0.0
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.
- data/.specification +58 -0
- data/History.txt +4 -0
- data/Manifest.txt +52 -0
- data/PostInstall.txt +4 -0
- data/README.rdoc +77 -0
- data/Rakefile +25 -0
- data/bin/summon +10 -0
- data/bin/summonh +19 -0
- data/ispec/integration_spec.rb +61 -0
- data/lib/summon.rb +41 -0
- data/lib/summon/cli.rb +136 -0
- data/lib/summon/log.rb +40 -0
- data/lib/summon/schema.rb +109 -0
- data/lib/summon/schema/availability.rb +14 -0
- data/lib/summon/schema/citation.rb +11 -0
- data/lib/summon/schema/date.rb +23 -0
- data/lib/summon/schema/document.rb +84 -0
- data/lib/summon/schema/error.rb +4 -0
- data/lib/summon/schema/facet.rb +51 -0
- data/lib/summon/schema/query.rb +96 -0
- data/lib/summon/schema/range.rb +52 -0
- data/lib/summon/schema/search.rb +37 -0
- data/lib/summon/schema/suggestion.rb +5 -0
- data/lib/summon/service.rb +44 -0
- data/lib/summon/transport.rb +13 -0
- data/lib/summon/transport/canned.json +2327 -0
- data/lib/summon/transport/canned.rb +9 -0
- data/lib/summon/transport/errors.rb +12 -0
- data/lib/summon/transport/headers.rb +55 -0
- data/lib/summon/transport/http.rb +114 -0
- data/lib/summon/transport/qstring.rb +49 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/summon/log_spec.rb +28 -0
- data/spec/summon/schema/availability_spec.rb +31 -0
- data/spec/summon/schema/citation_spec.rb +34 -0
- data/spec/summon/schema/date_spec.rb +12 -0
- data/spec/summon/schema/document_spec.rb +235 -0
- data/spec/summon/schema/facet_spec.rb +115 -0
- data/spec/summon/schema/query_spec.rb +163 -0
- data/spec/summon/schema/range_spec.rb +45 -0
- data/spec/summon/schema/search_spec.rb +62 -0
- data/spec/summon/schema_spec.rb +143 -0
- data/spec/summon/service_spec.rb +18 -0
- data/spec/summon/transport/headers_spec.rb +47 -0
- data/spec/summon/transport/http_spec.rb +29 -0
- data/spec/summon/transport/qstring_spec.rb +24 -0
- data/spec/summon_spec.rb +48 -0
- data/summon.gemspec +41 -0
- metadata +145 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Facet do
|
4
|
+
|
5
|
+
it "should map" do
|
6
|
+
facet = Summon::Facet.new(JSON.parse(EXAMPLE_FACET_JSON))
|
7
|
+
facet.remove_src
|
8
|
+
facet.counts.each {|f| f.remove_src }
|
9
|
+
facet.to_yaml.should == EXPECTED_FACET_YAML
|
10
|
+
|
11
|
+
first = facet.counts.first
|
12
|
+
first.apply_command.should == "addFacetValueFilter(ContentType_sfacet,Book,false)"
|
13
|
+
first.apply_negated_command.should == "addFacetValueFilter(ContentType_sfacet,Book,true)"
|
14
|
+
first.remove_command.should == "eatMyShorts()"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should now how to escape values" do
|
18
|
+
count = Summon::FacetCount.new(:value => "the quick, brown, fox")
|
19
|
+
count.value.should == "the quick, brown, fox"
|
20
|
+
count.escaped_value.should == 'the quick\, brown\, fox'
|
21
|
+
|
22
|
+
Summon::FacetCount.new(:value => ': everything (else) and $1 or {is} it\ ').escaped_value.should ==
|
23
|
+
'\: everything \(else\) and \$1 or \{is\} it\\ '
|
24
|
+
end
|
25
|
+
|
26
|
+
EXAMPLE_FACET_JSON = <<-JSON
|
27
|
+
{
|
28
|
+
"pageSize": 10,
|
29
|
+
"displayName": "ContentType",
|
30
|
+
"combineMode": "or",
|
31
|
+
"pageNumber": 1,
|
32
|
+
"listValuesCommand": "listFacetValues(ContentType_sfacet,or)",
|
33
|
+
"hasAppliedValue": false,
|
34
|
+
"fieldName": "ContentType_sfacet",
|
35
|
+
"hasLimitingValue": true,
|
36
|
+
"removeCommand": "removeFacetField(ContentType_sfacet)",
|
37
|
+
"removeValueFiltersCommand": "removeFacetValueFilters(ContentType)",
|
38
|
+
"counts": [
|
39
|
+
{
|
40
|
+
"isFurtherLimiting": true,
|
41
|
+
"isNegated": false,
|
42
|
+
"value": "Book",
|
43
|
+
"count": 799602,
|
44
|
+
"applyCommand": "addFacetValueFilter(ContentType_sfacet,Book,false)",
|
45
|
+
"removeCommand": "eatMyShorts()",
|
46
|
+
"applyNegatedCommand": "addFacetValueFilter(ContentType_sfacet,Book,true)",
|
47
|
+
"isApplied": false
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"isFurtherLimiting": true,
|
51
|
+
"isNegated": false,
|
52
|
+
"value": "JournalArticle",
|
53
|
+
"count": 49765,
|
54
|
+
"applyCommand": "addFacetValueFilter(ContentType_sfacet,JournalArticle,false)",
|
55
|
+
"removeCommand": "eatMyShorts()",
|
56
|
+
"applyNegatedCommand": "addFacetValueFilter(ContentType_sfacet,JournalArticle,true)",
|
57
|
+
"isApplied": false
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"isFurtherLimiting": true,
|
61
|
+
"isNegated": false,
|
62
|
+
"value": "Journal Article",
|
63
|
+
"count": 179002,
|
64
|
+
"removeCommand": "eatMyShorts()",
|
65
|
+
"applyCommand": "addFacetValueFilter(ContentType_sfacet,Journal Article,false)",
|
66
|
+
"applyNegatedCommand": "addFacetValueFilter(ContentType_sfacet,Journal Article,true)",
|
67
|
+
"isApplied": false
|
68
|
+
}
|
69
|
+
]
|
70
|
+
}
|
71
|
+
JSON
|
72
|
+
|
73
|
+
EXPECTED_FACET_YAML = <<-YAML
|
74
|
+
--- !ruby/object:Summon::Facet
|
75
|
+
combine_mode: or
|
76
|
+
counts:
|
77
|
+
- !ruby/object:Summon::FacetCount
|
78
|
+
applied: false
|
79
|
+
apply_command: addFacetValueFilter(ContentType_sfacet,Book,false)
|
80
|
+
apply_negated_command: addFacetValueFilter(ContentType_sfacet,Book,true)
|
81
|
+
count: 799602
|
82
|
+
further_limiting: true
|
83
|
+
negated: false
|
84
|
+
remove_command: eatMyShorts()
|
85
|
+
src:
|
86
|
+
value: Book
|
87
|
+
- !ruby/object:Summon::FacetCount
|
88
|
+
applied: false
|
89
|
+
apply_command: addFacetValueFilter(ContentType_sfacet,JournalArticle,false)
|
90
|
+
apply_negated_command: addFacetValueFilter(ContentType_sfacet,JournalArticle,true)
|
91
|
+
count: 49765
|
92
|
+
further_limiting: true
|
93
|
+
negated: false
|
94
|
+
remove_command: eatMyShorts()
|
95
|
+
src:
|
96
|
+
value: JournalArticle
|
97
|
+
- !ruby/object:Summon::FacetCount
|
98
|
+
applied: false
|
99
|
+
apply_command: addFacetValueFilter(ContentType_sfacet,Journal Article,false)
|
100
|
+
apply_negated_command: addFacetValueFilter(ContentType_sfacet,Journal Article,true)
|
101
|
+
count: 179002
|
102
|
+
further_limiting: true
|
103
|
+
negated: false
|
104
|
+
remove_command: eatMyShorts()
|
105
|
+
src:
|
106
|
+
value: Journal Article
|
107
|
+
display_name: ContentType
|
108
|
+
field_name: ContentType_sfacet
|
109
|
+
page_number: 1
|
110
|
+
page_size: 10
|
111
|
+
remove_command: removeFacetField(ContentType_sfacet)
|
112
|
+
remove_value_filters_command: removeFacetValueFilters(ContentType)
|
113
|
+
src:
|
114
|
+
YAML
|
115
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Query do
|
4
|
+
it "maps" do
|
5
|
+
raw = JSON.parse(<<-JSON)
|
6
|
+
{
|
7
|
+
"searchTerms": [1],
|
8
|
+
"facetValueGroupFilters": [],
|
9
|
+
"queryString": "4",
|
10
|
+
"facetValueFilters": [],
|
11
|
+
"textQueries": [6],
|
12
|
+
"textFilters": [7],
|
13
|
+
"rangeFilters": [],
|
14
|
+
"facetFields": [8],
|
15
|
+
"rangeFacetFields": [9],
|
16
|
+
"sort": [
|
17
|
+
{
|
18
|
+
"fieldName": "PublicationDate_dt",
|
19
|
+
"sortOrder": "desc"
|
20
|
+
}
|
21
|
+
],
|
22
|
+
"params": [11]
|
23
|
+
}
|
24
|
+
JSON
|
25
|
+
|
26
|
+
|
27
|
+
query(raw).with {
|
28
|
+
search_terms.should == [1]
|
29
|
+
range_filters.should == []
|
30
|
+
facet_value_group_filters.should == []
|
31
|
+
query_string.should == "4"
|
32
|
+
facet_value_filters.should == []
|
33
|
+
text_queries.should == [6]
|
34
|
+
text_filters.should == [7]
|
35
|
+
facet_fields.should == [8]
|
36
|
+
sorts.length.should == 1
|
37
|
+
sort.field_name.should == "PublicationDate_dt"
|
38
|
+
sort.sort_order.should == "desc"
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should map facet value fields and facet group fields" do
|
43
|
+
q = query(
|
44
|
+
"searchTerms"=>[], "rangeFilters"=>[],
|
45
|
+
"facetValueGroupFilters"=>[
|
46
|
+
{
|
47
|
+
"combineMode"=>"or", "tag"=>"3",
|
48
|
+
"values"=>[
|
49
|
+
{"value"=>"history", "removeCommand"=>"removeFacetValueGroupFilter(3,history)"},
|
50
|
+
{"value"=>"uk", "removeCommand"=>"removeFacetValueGroupFilter(3,uk)"}
|
51
|
+
],
|
52
|
+
"removeCommand"=>"removeFacetValueGroupFilter(3)",
|
53
|
+
"fieldName"=>"SubjectTerms"
|
54
|
+
}
|
55
|
+
],
|
56
|
+
"facetValueFilters"=>[
|
57
|
+
{
|
58
|
+
"isNegated"=>false,
|
59
|
+
"value"=>"law",
|
60
|
+
"removeCommand"=>"removeFacetValueFilter(SubjectTerms,law)",
|
61
|
+
"fieldName"=>"SubjectTerms",
|
62
|
+
"negateCommand"=>"negateFacetValueFilter(SubjectTerms,law)"
|
63
|
+
}
|
64
|
+
],
|
65
|
+
"queryString"=>"s.fvgf%3A3=SubjectTerms%2Cor%2Chistory%2Cuk&s.ff=SubjectTerms%2Cand%2C1%2C10&s.fvf=SubjectTerms%2Claw%2Cfalse",
|
66
|
+
"facetFields"=>[{
|
67
|
+
"pageSize"=>10, "pageNumber"=>1, "combineMode"=>"and", "removeCommand"=>"removeFacetField(SubjectTerms)", "fieldName"=>"SubjectTerms"
|
68
|
+
}],
|
69
|
+
"textFilters"=>[], "textQueries"=>[], "sort"=>[], "rangeFacetFields"=>[]
|
70
|
+
)
|
71
|
+
filter = q.facet_value_filters[0]
|
72
|
+
filter.should_not be_negated
|
73
|
+
filter.remove_command.should == "removeFacetValueFilter(SubjectTerms,law)"
|
74
|
+
filter.field_name.should == "SubjectTerms"
|
75
|
+
filter.negate_command.should == "negateFacetValueFilter(SubjectTerms,law)"
|
76
|
+
|
77
|
+
group = q.facet_value_group_filters[0]
|
78
|
+
group.combine_mode.should == "or"
|
79
|
+
group.tag.should == "3"
|
80
|
+
group.remove_command.should == "removeFacetValueGroupFilter(3)"
|
81
|
+
group.field_name.should == "SubjectTerms"
|
82
|
+
|
83
|
+
group.values[0].value.should == "history"
|
84
|
+
group.values[0].remove_command.should == "removeFacetValueGroupFilter(3,history)"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should be able to deescape a string" do
|
88
|
+
query_hash("").should == {}
|
89
|
+
query_hash("s.fq=Author_t%3A%28Linster%2C+Richard+L%29").should == {"s.fq" => "Author_t:(Linster, Richard L)"}
|
90
|
+
query_hash("s.fq=Balthazar&s.fq=Author_t%3A%28Linster%2C+Richard+L%29").should == {"s.fq" => ["Balthazar", "Author_t:(Linster, Richard L)"]}
|
91
|
+
query_hash("s.fq=Author_t%3A%28Linster%2C+Richard+L%29&s.q=Probability+models+of+recidivism%5C%3A+an+exploration").should ==
|
92
|
+
{"s.fq" => "Author_t:(Linster, Richard L)", "s.q" => "Probability models of recidivism\\: an exploration"}
|
93
|
+
end
|
94
|
+
|
95
|
+
it "has params" do
|
96
|
+
query({
|
97
|
+
:params => [
|
98
|
+
{
|
99
|
+
"key" => "holdingsOnly",
|
100
|
+
"value" => "t",
|
101
|
+
"removeCommand" => "removeParameter(holdingsOnly)"
|
102
|
+
}
|
103
|
+
]
|
104
|
+
}).tap do |q|
|
105
|
+
q.params.should_not be(nil)
|
106
|
+
# what's the deal w/ holdings??? should we delete this test? - jl
|
107
|
+
# q.should be_holdings_only_enabled
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "knows it's own date_min and date_max" do
|
112
|
+
query({
|
113
|
+
:rangeFilters => [
|
114
|
+
{
|
115
|
+
"fieldName" => "PublicationDate",
|
116
|
+
"range" => {
|
117
|
+
"minValue" => "2000",
|
118
|
+
"maxValue" => "2008"
|
119
|
+
}
|
120
|
+
}
|
121
|
+
]
|
122
|
+
}).tap do |q|
|
123
|
+
q.date_min.should == 2000
|
124
|
+
q.date_max.should == 2008
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "doesn't get phased when one of the ranges in unbounded" do
|
129
|
+
query({
|
130
|
+
:rangeFilters => [
|
131
|
+
{
|
132
|
+
"fieldName" => "PublicationDate",
|
133
|
+
"range" => {
|
134
|
+
"minValue" => "*",
|
135
|
+
"maxValue" => "2008"
|
136
|
+
}
|
137
|
+
}
|
138
|
+
]
|
139
|
+
}).tap do |q|
|
140
|
+
q.date_min.should be_nil
|
141
|
+
q.date_max.should == 2008
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should know about holdings only" do
|
146
|
+
query({}).should_not be_holdings_only_enabled
|
147
|
+
query(:isHoldingsOnlyEnabled => true).should be_holdings_only_enabled
|
148
|
+
query(:isHoldingsOnlyEnabled => false).should_not be_holdings_only_enabled
|
149
|
+
end
|
150
|
+
|
151
|
+
def query_hash(str)
|
152
|
+
query(:queryString => str).to_hash
|
153
|
+
end
|
154
|
+
|
155
|
+
def query(params)
|
156
|
+
Summon::Query.new(params)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
class Object
|
162
|
+
alias_method :with, :instance_eval
|
163
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::RangeFacet do
|
4
|
+
it "maps" do
|
5
|
+
range = Summon::RangeFacet.new(JSON.parse(<<-JSON))
|
6
|
+
{
|
7
|
+
"displayName": "PublicationDate",
|
8
|
+
"removeCommand": "removeFacetField(PublicationDate)",
|
9
|
+
"fieldName": "PublicationDate_dt",
|
10
|
+
"counts": [
|
11
|
+
{
|
12
|
+
"count": 119795,
|
13
|
+
"applyCommand": "addRangeFilter(PublicationDate,1999:1999)",
|
14
|
+
"range": {
|
15
|
+
"minValue": "1999",
|
16
|
+
"maxValue": "2000"
|
17
|
+
},
|
18
|
+
"isApplied": true
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"count": 122712,
|
22
|
+
"applyCommand": "addRangeFilter(PublicationDate,2000:2000)",
|
23
|
+
"range": {
|
24
|
+
"minValue": "2000",
|
25
|
+
"maxValue": "2001"
|
26
|
+
},
|
27
|
+
"isApplied": false
|
28
|
+
}
|
29
|
+
]
|
30
|
+
}
|
31
|
+
JSON
|
32
|
+
range.display_name.should == "PublicationDate"
|
33
|
+
range.remove_command.should == "removeFacetField(PublicationDate)"
|
34
|
+
range.field_name.should == "PublicationDate_dt"
|
35
|
+
range.counts.should_not be_nil
|
36
|
+
range.counts.length.should be(2)
|
37
|
+
range.counts[0].tap do |c|
|
38
|
+
c.count.should == 119795
|
39
|
+
c.apply_command.should == "addRangeFilter(PublicationDate,1999:1999)"
|
40
|
+
c.min.should == "1999"
|
41
|
+
c.max.should == "2000"
|
42
|
+
c.should be_applied
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Search do
|
4
|
+
it "maps" do
|
5
|
+
search = Summon::Search.new(JSON.parse(<<-JSON))
|
6
|
+
{
|
7
|
+
"pageCount": 0,
|
8
|
+
"didYouMeanSuggestions": [
|
9
|
+
|
10
|
+
],
|
11
|
+
"fullTextCount": 0,
|
12
|
+
"queryTime": 124,
|
13
|
+
"documents": [],
|
14
|
+
"totalRequestTime": 129,
|
15
|
+
"elapsedQueryTime": 126,
|
16
|
+
"version": "1.0.0",
|
17
|
+
"facetFields": [
|
18
|
+
],
|
19
|
+
"rangeFacetFields": [
|
20
|
+
|
21
|
+
],
|
22
|
+
"recordCount": 4589937,
|
23
|
+
"sessionId": "cfaa4020-1abe-4a9d-ae6e-e433a36c1069",
|
24
|
+
"query": {}
|
25
|
+
}
|
26
|
+
JSON
|
27
|
+
search.page_count.should == 0
|
28
|
+
search.record_count.should == 4589937
|
29
|
+
search.query_time.should == 124
|
30
|
+
search.session_id.should == "cfaa4020-1abe-4a9d-ae6e-e433a36c1069"
|
31
|
+
search.documents.should == []
|
32
|
+
search.version.should == "1.0.0"
|
33
|
+
search.query.should be_kind_of(Summon::Query)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should handle an error case" do
|
37
|
+
search = Summon::Search.new(
|
38
|
+
"version" => "1.0.0",
|
39
|
+
"errors" => [
|
40
|
+
{
|
41
|
+
"suggestion" => {
|
42
|
+
"applySuggestionCommand" => "removeTextQuery(foo\:bar) addTextQuery(foo\\\:bar)",
|
43
|
+
"suggestedQuery" => "foo\:bar",
|
44
|
+
"originalQuery" => "foo:bar"
|
45
|
+
},
|
46
|
+
"message" => "Unknown search field(s): foo."
|
47
|
+
}])
|
48
|
+
search.version.should == "1.0.0"
|
49
|
+
search.record_count.should == 0
|
50
|
+
search.errors.size.should == 1
|
51
|
+
search.errors.first.message.should == "Unknown search field(s): foo."
|
52
|
+
search.errors.first.suggestion.apply_suggestion_command.should == "removeTextQuery(foo\:bar) addTextQuery(foo\\\:bar)"
|
53
|
+
search.errors.first.suggestion.suggested_query.should == "foo\:bar"
|
54
|
+
search.errors.first.suggestion.original_query.should == "foo:bar"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should be empty w/ no docs" do
|
58
|
+
Summon::Search.new({}).should be_empty
|
59
|
+
Summon::Search.new({"documents" => [{}]}).should_not be_empty
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Schema do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@class = Class.new(Summon::Schema)
|
7
|
+
end
|
8
|
+
|
9
|
+
def class_eval(&block)
|
10
|
+
@class.class_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def init(values)
|
14
|
+
@class.new(values)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "pulls its attributes from a hash" do
|
18
|
+
class_eval do
|
19
|
+
attr :foo
|
20
|
+
attr :baz
|
21
|
+
end
|
22
|
+
|
23
|
+
init(:foo => "bar", :baz => "bang").foo.should == "bar"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can pull its attributes from string keys as well as symbol keys" do
|
27
|
+
class_eval do
|
28
|
+
attr :foo
|
29
|
+
end
|
30
|
+
|
31
|
+
init("foo" => "bar").foo.should == "bar"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "knows how to atomagically map between camel case and perl case" do
|
35
|
+
class_eval do
|
36
|
+
attr :foo_bar_baz
|
37
|
+
end
|
38
|
+
|
39
|
+
init("fooBarBaz" => "Hello").foo_bar_baz.should == "Hello"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can also magically convert from Pascal case as well" do
|
43
|
+
class_eval do
|
44
|
+
attr :foo_bar_baz
|
45
|
+
end
|
46
|
+
init("FooBarBaz" => "Hello").foo_bar_baz.should == "Hello"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "can have an overridden field name for names that don't map so cleanly" do
|
50
|
+
class_eval do
|
51
|
+
attr :isbn, :json_name => "ISBN"
|
52
|
+
attr :eissn, :json_name => "eISSN"
|
53
|
+
end
|
54
|
+
|
55
|
+
o = init("ISBN" => 123456, "eISSN" => 98765)
|
56
|
+
o.isbn.should == 123456
|
57
|
+
o.eissn.should == 98765
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "transforms" do
|
61
|
+
it "can transform subobjects" do
|
62
|
+
class Summon::DogPile < Summon::Schema
|
63
|
+
attr :type
|
64
|
+
end
|
65
|
+
class_eval do
|
66
|
+
attr :steaming, :transform => :DogPile
|
67
|
+
end
|
68
|
+
|
69
|
+
o = init("steaming" => {:type => "swirled"})
|
70
|
+
o.steaming.should_not be_nil
|
71
|
+
o.steaming.type.should == "swirled"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "will apply a transform across an array if the field is an array" do
|
75
|
+
class Summon::DogPatch < Summon::Schema
|
76
|
+
attr :foo
|
77
|
+
end
|
78
|
+
class_eval do
|
79
|
+
attr :patches, :transform => :DogPatch
|
80
|
+
end
|
81
|
+
patches = init("patches" => [{:foo => 'bar'},{:foo => 'baz'}, {:foo => 'bang'}]).patches
|
82
|
+
patches.should_not be_nil
|
83
|
+
patches.should be_kind_of(Array)
|
84
|
+
patches.collect{|p| p.foo}.should == ['bar', 'baz', 'bang']
|
85
|
+
end
|
86
|
+
|
87
|
+
it "will ignore a transform if the element is not present" do
|
88
|
+
class Summon::DogFood < Summon::Schema
|
89
|
+
attr :foo
|
90
|
+
end
|
91
|
+
class_eval do
|
92
|
+
attr :kibbles, :transform => :DogPatch
|
93
|
+
attr :bits, :single => true, :transform => :DogPatch
|
94
|
+
end
|
95
|
+
foo = init({})
|
96
|
+
foo.kibbles.should == []
|
97
|
+
foo.bits.should == nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "will create a predicate if the field is marked as boolean" do
|
102
|
+
class_eval do
|
103
|
+
attr :boollocks, :boolean => true
|
104
|
+
end
|
105
|
+
|
106
|
+
init("isBoollocks" => true).boollocks?.should be(true)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "will automatically do a bean styles lookup on attributes that end in a question mark" do
|
110
|
+
class_eval do
|
111
|
+
attr :awesome?
|
112
|
+
end
|
113
|
+
init("isAwesome" => true).should be_awesome
|
114
|
+
init("isAwesome" => false).should_not be_awesome
|
115
|
+
end
|
116
|
+
|
117
|
+
it "automatically unwraps arrays from values if the value is marked as being single" do
|
118
|
+
class_eval do
|
119
|
+
attr :just_one, :single => true
|
120
|
+
end
|
121
|
+
init(:justOne => ["foo"]).just_one.should == 'foo'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "defaults to automatically unwrap arrays if the field doesn't end in s" do
|
125
|
+
class_eval do
|
126
|
+
attr :foo
|
127
|
+
attr :foos
|
128
|
+
end
|
129
|
+
o = init(:foo => ["bar"], :foos => ["bar"])
|
130
|
+
o.foo.should == "bar"
|
131
|
+
o.foos.should == ["bar"]
|
132
|
+
end
|
133
|
+
|
134
|
+
it "initializes multi-valued fields to the empty array if it is not present" do
|
135
|
+
class_eval do
|
136
|
+
attr :foos
|
137
|
+
end
|
138
|
+
init({}).foos.should == []
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
end
|