summon 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|