speedy-af 0.4.0 → 0.5.1

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.
@@ -0,0 +1,66 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+
3
+ <!--
4
+ * Licensed to the Apache Software Foundation (ASF) under one or more
5
+ * contributor license agreements. See the NOTICE file distributed with
6
+ * this work for additional information regarding copyright ownership.
7
+ * The ASF licenses this file to You under the Apache License, Version 2.0
8
+ * (the "License"); you may not use this file except in compliance with
9
+ * the License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ -->
19
+
20
+ <!--
21
+ Simple transform of Solr query results to RSS
22
+ -->
23
+
24
+ <xsl:stylesheet version='1.0'
25
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
26
+
27
+ <xsl:output
28
+ method="xml"
29
+ encoding="utf-8"
30
+ media-type="text/xml; charset=UTF-8"
31
+ />
32
+ <xsl:template match='/'>
33
+ <rss version="2.0">
34
+ <channel>
35
+ <title>Example Solr RSS 2.0 Feed</title>
36
+ <link>http://localhost:8983/solr</link>
37
+ <description>
38
+ This has been formatted by the sample "example_rss.xsl" transform -
39
+ use your own XSLT to get a nicer RSS feed.
40
+ </description>
41
+ <language>en-us</language>
42
+ <docs>http://localhost:8983/solr</docs>
43
+ <xsl:apply-templates select="response/result/doc"/>
44
+ </channel>
45
+ </rss>
46
+ </xsl:template>
47
+
48
+ <!-- search results xslt -->
49
+ <xsl:template match="doc">
50
+ <xsl:variable name="id" select="str[@name='id']"/>
51
+ <xsl:variable name="timestamp" select="date[@name='timestamp']"/>
52
+ <item>
53
+ <title><xsl:value-of select="str[@name='name']"/></title>
54
+ <link>
55
+ http://localhost:8983/solr/select?q=id:<xsl:value-of select="$id"/>
56
+ </link>
57
+ <description>
58
+ <xsl:value-of select="arr[@name='features']"/>
59
+ </description>
60
+ <pubDate><xsl:value-of select="$timestamp"/></pubDate>
61
+ <guid>
62
+ http://localhost:8983/solr/select?q=id:<xsl:value-of select="$id"/>
63
+ </guid>
64
+ </item>
65
+ </xsl:template>
66
+ </xsl:stylesheet>
@@ -0,0 +1,337 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ Licensed to the Apache Software Foundation (ASF) under one or more
4
+ contributor license agreements. See the NOTICE file distributed with
5
+ this work for additional information regarding copyright ownership.
6
+ The ASF licenses this file to You under the Apache License, Version 2.0
7
+ (the "License"); you may not use this file except in compliance with
8
+ the License. You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ -->
18
+
19
+
20
+ <!--
21
+ Display the luke request handler with graphs
22
+ -->
23
+ <xsl:stylesheet
24
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
25
+ xmlns="http://www.w3.org/1999/xhtml"
26
+ version="1.0"
27
+ >
28
+ <xsl:output
29
+ method="html"
30
+ encoding="UTF-8"
31
+ media-type="text/html; charset=UTF-8"
32
+ doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
33
+ doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
34
+ />
35
+
36
+ <xsl:variable name="title">Solr Luke Request Handler Response</xsl:variable>
37
+
38
+ <xsl:template match="/">
39
+ <html xmlns="http://www.w3.org/1999/xhtml">
40
+ <head>
41
+ <link rel="stylesheet" type="text/css" href="solr-admin.css"/>
42
+ <link rel="icon" href="favicon.ico" type="image/ico"/>
43
+ <link rel="shortcut icon" href="favicon.ico" type="image/ico"/>
44
+ <title>
45
+ <xsl:value-of select="$title"/>
46
+ </title>
47
+ <xsl:call-template name="css"/>
48
+
49
+ </head>
50
+ <body>
51
+ <h1>
52
+ <xsl:value-of select="$title"/>
53
+ </h1>
54
+ <div class="doc">
55
+ <ul>
56
+ <xsl:if test="response/lst[@name='index']">
57
+ <li>
58
+ <a href="#index">Index Statistics</a>
59
+ </li>
60
+ </xsl:if>
61
+ <xsl:if test="response/lst[@name='fields']">
62
+ <li>
63
+ <a href="#fields">Field Statistics</a>
64
+ <ul>
65
+ <xsl:for-each select="response/lst[@name='fields']/lst">
66
+ <li>
67
+ <a href="#{@name}">
68
+ <xsl:value-of select="@name"/>
69
+ </a>
70
+ </li>
71
+ </xsl:for-each>
72
+ </ul>
73
+ </li>
74
+ </xsl:if>
75
+ <xsl:if test="response/lst[@name='doc']">
76
+ <li>
77
+ <a href="#doc">Document statistics</a>
78
+ </li>
79
+ </xsl:if>
80
+ </ul>
81
+ </div>
82
+ <xsl:if test="response/lst[@name='index']">
83
+ <h2><a name="index"/>Index Statistics</h2>
84
+ <xsl:apply-templates select="response/lst[@name='index']"/>
85
+ </xsl:if>
86
+ <xsl:if test="response/lst[@name='fields']">
87
+ <h2><a name="fields"/>Field Statistics</h2>
88
+ <xsl:apply-templates select="response/lst[@name='fields']"/>
89
+ </xsl:if>
90
+ <xsl:if test="response/lst[@name='doc']">
91
+ <h2><a name="doc"/>Document statistics</h2>
92
+ <xsl:apply-templates select="response/lst[@name='doc']"/>
93
+ </xsl:if>
94
+ </body>
95
+ </html>
96
+ </xsl:template>
97
+
98
+ <xsl:template match="lst">
99
+ <xsl:if test="parent::lst">
100
+ <tr>
101
+ <td colspan="2">
102
+ <div class="doc">
103
+ <xsl:call-template name="list"/>
104
+ </div>
105
+ </td>
106
+ </tr>
107
+ </xsl:if>
108
+ <xsl:if test="not(parent::lst)">
109
+ <div class="doc">
110
+ <xsl:call-template name="list"/>
111
+ </div>
112
+ </xsl:if>
113
+ </xsl:template>
114
+
115
+ <xsl:template name="list">
116
+ <xsl:if test="count(child::*)>0">
117
+ <table>
118
+ <thead>
119
+ <tr>
120
+ <th colspan="2">
121
+ <p>
122
+ <a name="{@name}"/>
123
+ </p>
124
+ <xsl:value-of select="@name"/>
125
+ </th>
126
+ </tr>
127
+ </thead>
128
+ <tbody>
129
+ <xsl:choose>
130
+ <xsl:when
131
+ test="@name='histogram'">
132
+ <tr>
133
+ <td colspan="2">
134
+ <xsl:call-template name="histogram"/>
135
+ </td>
136
+ </tr>
137
+ </xsl:when>
138
+ <xsl:otherwise>
139
+ <xsl:apply-templates/>
140
+ </xsl:otherwise>
141
+ </xsl:choose>
142
+ </tbody>
143
+ </table>
144
+ </xsl:if>
145
+ </xsl:template>
146
+
147
+ <xsl:template name="histogram">
148
+ <div class="doc">
149
+ <xsl:call-template name="barchart">
150
+ <xsl:with-param name="max_bar_width">50</xsl:with-param>
151
+ <xsl:with-param name="iwidth">800</xsl:with-param>
152
+ <xsl:with-param name="iheight">160</xsl:with-param>
153
+ <xsl:with-param name="fill">blue</xsl:with-param>
154
+ </xsl:call-template>
155
+ </div>
156
+ </xsl:template>
157
+
158
+ <xsl:template name="barchart">
159
+ <xsl:param name="max_bar_width"/>
160
+ <xsl:param name="iwidth"/>
161
+ <xsl:param name="iheight"/>
162
+ <xsl:param name="fill"/>
163
+ <xsl:variable name="max">
164
+ <xsl:for-each select="int">
165
+ <xsl:sort data-type="number" order="descending"/>
166
+ <xsl:if test="position()=1">
167
+ <xsl:value-of select="."/>
168
+ </xsl:if>
169
+ </xsl:for-each>
170
+ </xsl:variable>
171
+ <xsl:variable name="bars">
172
+ <xsl:value-of select="count(int)"/>
173
+ </xsl:variable>
174
+ <xsl:variable name="bar_width">
175
+ <xsl:choose>
176
+ <xsl:when test="$max_bar_width &lt; ($iwidth div $bars)">
177
+ <xsl:value-of select="$max_bar_width"/>
178
+ </xsl:when>
179
+ <xsl:otherwise>
180
+ <xsl:value-of select="$iwidth div $bars"/>
181
+ </xsl:otherwise>
182
+ </xsl:choose>
183
+ </xsl:variable>
184
+ <table class="histogram">
185
+ <tbody>
186
+ <tr>
187
+ <xsl:for-each select="int">
188
+ <td>
189
+ <xsl:value-of select="."/>
190
+ <div class="histogram">
191
+ <xsl:attribute name="style">background-color: <xsl:value-of select="$fill"/>; width: <xsl:value-of select="$bar_width"/>px; height: <xsl:value-of select="($iheight*number(.)) div $max"/>px;</xsl:attribute>
192
+ </div>
193
+ </td>
194
+ </xsl:for-each>
195
+ </tr>
196
+ <tr>
197
+ <xsl:for-each select="int">
198
+ <td>
199
+ <xsl:value-of select="@name"/>
200
+ </td>
201
+ </xsl:for-each>
202
+ </tr>
203
+ </tbody>
204
+ </table>
205
+ </xsl:template>
206
+
207
+ <xsl:template name="keyvalue">
208
+ <xsl:choose>
209
+ <xsl:when test="@name">
210
+ <tr>
211
+ <td class="name">
212
+ <xsl:value-of select="@name"/>
213
+ </td>
214
+ <td class="value">
215
+ <xsl:value-of select="."/>
216
+ </td>
217
+ </tr>
218
+ </xsl:when>
219
+ <xsl:otherwise>
220
+ <xsl:value-of select="."/>
221
+ </xsl:otherwise>
222
+ </xsl:choose>
223
+ </xsl:template>
224
+
225
+ <xsl:template match="int|bool|long|float|double|uuid|date">
226
+ <xsl:call-template name="keyvalue"/>
227
+ </xsl:template>
228
+
229
+ <xsl:template match="arr">
230
+ <tr>
231
+ <td class="name">
232
+ <xsl:value-of select="@name"/>
233
+ </td>
234
+ <td class="value">
235
+ <ul>
236
+ <xsl:for-each select="child::*">
237
+ <li>
238
+ <xsl:apply-templates/>
239
+ </li>
240
+ </xsl:for-each>
241
+ </ul>
242
+ </td>
243
+ </tr>
244
+ </xsl:template>
245
+
246
+ <xsl:template match="str">
247
+ <xsl:choose>
248
+ <xsl:when test="@name='schema' or @name='index' or @name='flags'">
249
+ <xsl:call-template name="schema"/>
250
+ </xsl:when>
251
+ <xsl:otherwise>
252
+ <xsl:call-template name="keyvalue"/>
253
+ </xsl:otherwise>
254
+ </xsl:choose>
255
+ </xsl:template>
256
+
257
+ <xsl:template name="schema">
258
+ <tr>
259
+ <td class="name">
260
+ <xsl:value-of select="@name"/>
261
+ </td>
262
+ <td class="value">
263
+ <xsl:if test="contains(.,'unstored')">
264
+ <xsl:value-of select="."/>
265
+ </xsl:if>
266
+ <xsl:if test="not(contains(.,'unstored'))">
267
+ <xsl:call-template name="infochar2string">
268
+ <xsl:with-param name="charList">
269
+ <xsl:value-of select="."/>
270
+ </xsl:with-param>
271
+ </xsl:call-template>
272
+ </xsl:if>
273
+ </td>
274
+ </tr>
275
+ </xsl:template>
276
+
277
+ <xsl:template name="infochar2string">
278
+ <xsl:param name="i">1</xsl:param>
279
+ <xsl:param name="charList"/>
280
+
281
+ <xsl:variable name="char">
282
+ <xsl:value-of select="substring($charList,$i,1)"/>
283
+ </xsl:variable>
284
+ <xsl:choose>
285
+ <xsl:when test="$char='I'">
286
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='I']"/> - </xsl:when>
287
+ <xsl:when test="$char='T'">
288
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='T']"/> - </xsl:when>
289
+ <xsl:when test="$char='S'">
290
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='S']"/> - </xsl:when>
291
+ <xsl:when test="$char='M'">
292
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='M']"/> - </xsl:when>
293
+ <xsl:when test="$char='V'">
294
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='V']"/> - </xsl:when>
295
+ <xsl:when test="$char='o'">
296
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='o']"/> - </xsl:when>
297
+ <xsl:when test="$char='p'">
298
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='p']"/> - </xsl:when>
299
+ <xsl:when test="$char='O'">
300
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='O']"/> - </xsl:when>
301
+ <xsl:when test="$char='L'">
302
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='L']"/> - </xsl:when>
303
+ <xsl:when test="$char='B'">
304
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='B']"/> - </xsl:when>
305
+ <xsl:when test="$char='C'">
306
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='C']"/> - </xsl:when>
307
+ <xsl:when test="$char='f'">
308
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='f']"/> - </xsl:when>
309
+ <xsl:when test="$char='l'">
310
+ <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='l']"/> -
311
+ </xsl:when>
312
+ </xsl:choose>
313
+
314
+ <xsl:if test="not($i>=string-length($charList))">
315
+ <xsl:call-template name="infochar2string">
316
+ <xsl:with-param name="i">
317
+ <xsl:value-of select="$i+1"/>
318
+ </xsl:with-param>
319
+ <xsl:with-param name="charList">
320
+ <xsl:value-of select="$charList"/>
321
+ </xsl:with-param>
322
+ </xsl:call-template>
323
+ </xsl:if>
324
+ </xsl:template>
325
+ <xsl:template name="css">
326
+ <style type="text/css">
327
+ <![CDATA[
328
+ td.name {font-style: italic; font-size:80%; }
329
+ .doc { margin: 0.5em; border: solid grey 1px; }
330
+ .exp { display: none; font-family: monospace; white-space: pre; }
331
+ div.histogram { background: none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;}
332
+ table.histogram { width: auto; vertical-align: bottom; }
333
+ table.histogram td, table.histogram th { text-align: center; vertical-align: bottom; border-bottom: 1px solid #ff9933; width: auto; }
334
+ ]]>
335
+ </style>
336
+ </xsl:template>
337
+ </xsl:stylesheet>
@@ -3,6 +3,10 @@ class IndexedFile < ActiveFedora::File
3
3
  include SpeedyAF::IndexedContent
4
4
  end
5
5
 
6
+ class SampleResource < ActiveFedora::File
7
+ include SpeedyAF::IndexedContent
8
+ end
9
+
6
10
  class Chapter < ActiveFedora::Base
7
11
  property :title, predicate: ::RDF::Vocab::DC.title, multiple: false do |index|
8
12
  index.as :stored_searchable
@@ -12,18 +16,23 @@ class Chapter < ActiveFedora::Base
12
16
  end
13
17
  end
14
18
 
15
- module DowncaseBehavior
19
+ module TitleBehavior
16
20
  def lowercase_title
17
21
  title.downcase
18
22
  end
23
+
24
+ def uppercase_title
25
+ title.upcase
26
+ end
19
27
  end
20
28
 
21
29
  class Book < ActiveFedora::Base
22
- include DowncaseBehavior
30
+ include TitleBehavior
23
31
  include SpeedyAF::OrderedAggregationIndex
24
32
 
25
33
  belongs_to :library, predicate: ::RDF::Vocab::DC.isPartOf
26
34
  has_subresource 'indexed_file', class_name: 'IndexedFile'
35
+ has_subresource 'descMetadata', class_name: 'SampleResource'
27
36
  has_subresource 'unindexed_file', class_name: 'ActiveFedora::File'
28
37
  property :title, predicate: ::RDF::Vocab::DC.title, multiple: false do |index|
29
38
  index.as :stored_searchable
@@ -33,14 +42,28 @@ class Book < ActiveFedora::Base
33
42
  end
34
43
  ordered_aggregation :chapters, through: :list_source
35
44
  indexed_ordered_aggregation :chapters
45
+ end
36
46
 
37
- def uppercase_title
38
- title.upcase
47
+ class Comic < ActiveFedora::Base
48
+ include TitleBehavior
49
+
50
+ belongs_to :library, predicate: ::RDF::Vocab::DC.isPartOf
51
+ belongs_to :comic_shop, predicate: ::RDF::Vocab::DC.isPartOf
52
+ property :title, predicate: ::RDF::Vocab::DC.title, multiple: false do |index|
53
+ index.as :stored_searchable
54
+ end
55
+ property :publisher, predicate: ::RDF::Vocab::DC.publisher, multiple: false do |index|
56
+ index.as :stored_searchable
39
57
  end
40
58
  end
41
59
 
42
60
  class Library < ActiveFedora::Base
43
- has_many :books, predicate: ::RDF::Vocab::DC.isPartOf
61
+ has_many :books, class_name: 'Book', predicate: ::RDF::Vocab::DC.isPartOf
62
+ has_many :comics, class_name: 'Comic', predicate: ::RDF::Vocab::DC.isPartOf
63
+ end
64
+
65
+ class ComicShop < ActiveFedora::Base
66
+ has_many :comics, predicate: ::RDF::Vocab::DC.isPartOf
44
67
  end
45
68
 
46
69
  module SpeedySpecs
@@ -3,11 +3,13 @@ require 'spec_helper'
3
3
  require 'rdf/vocab/dc'
4
4
 
5
5
  describe SpeedyAF::Base do
6
- before { load_fixture_classes! }
6
+ before { load_fixture_classes! }
7
7
  after { unload_fixture_classes! }
8
8
 
9
9
  let!(:library) { Library.create }
10
+ let!(:comic_shop) { ComicShop.create }
10
11
  let!(:book) { Book.new title: 'Ordered Things', publisher: 'ActiveFedora Performance LLC', library: library }
12
+ let!(:comic) { Comic.new title: 'Vestibulum velit nulla', publisher: 'SpeedyAF LLC', library: library, comic_shop: comic_shop }
11
13
  let!(:chapters) do
12
14
  [
13
15
  Chapter.create(title: 'Chapter 3', contributor: ['Hopper', 'Lovelace', 'Johnson']),
@@ -31,12 +33,22 @@ describe SpeedyAF::Base do
31
33
  Nigh tofth eliv ingdead.
32
34
  IPSUM
33
35
  end
36
+ let!(:metadata) do
37
+ <<-IPSUM
38
+ In scelerisque volutpat rutrum. Phasellus dictum velit at orci luctus convallis. Nulla rutrum
39
+ eget libero at sodales. Suspendisse potenti. Donec ut lobortis mi, ut venenatis diam. Phasellus
40
+ mi felis, cursus at lacinia vitae, aliquam vitae eros. Suspendisse tincidunt a massa in
41
+ condimentum. Nulla finibus risus quam, vel elementum enim sodales at.
42
+ IPSUM
43
+ end
34
44
  let(:book_presenter) { described_class.find(book.id) }
45
+ let(:comic_presenter) { described_class.find(comic.id) }
35
46
 
36
47
  context 'lightweight presenter' do
37
48
  before do
38
49
  book.indexed_file.content = indexed_content
39
50
  book.unindexed_file.content = unindexed_content
51
+ book.descMetadata.content = metadata
40
52
  book.chapters = chapters
41
53
  book.ordered_chapters = chapters.sort_by(&:title)
42
54
  book.save!
@@ -66,6 +78,7 @@ describe SpeedyAF::Base do
66
78
 
67
79
  context 'reflections' do
68
80
  let!(:library_presenter) { described_class.find(library.id) }
81
+ let!(:comic_shop_presenter) { described_class.find(comic_shop.id) }
69
82
 
70
83
  it 'loads via indexed proxies' do
71
84
  expect(book_presenter.chapter_ids).to match_array(book.chapter_ids)
@@ -82,27 +95,38 @@ describe SpeedyAF::Base do
82
95
 
83
96
  it 'loads indexed subresources' do
84
97
  ipsum_presenter = book_presenter.indexed_file
98
+ lorem_presenter = book_presenter.descMetadata
85
99
  expect(ipsum_presenter.model).to eq(IndexedFile)
100
+ expect(lorem_presenter.model).to eq(SampleResource)
86
101
  expect(ipsum_presenter.content).to eq(indexed_content)
102
+ expect(lorem_presenter.content).to eq(metadata)
87
103
  expect(book_presenter).not_to be_real
88
104
  expect(ipsum_presenter).not_to be_real
105
+ expect(lorem_presenter).not_to be_real
89
106
  end
90
107
 
91
108
  it 'loads has_many reflections' do
92
109
  library.books.create(title: 'Ordered Things II')
110
+ library.comics.create(title: 'Comet in Moominland')
93
111
  library.save
94
- presenter = library_presenter.books
95
- expect(presenter.length).to eq(2)
96
- expect(presenter.all? { |bp| bp.is_a?(described_class) }).to be_truthy
112
+ expect(library_presenter.books.length).to eq(2)
113
+ expect(library_presenter.books.all? { |bp| bp.is_a?(described_class) }).to be_truthy
97
114
  expect(library_presenter.book_ids).to match_array(library.book_ids)
115
+ expect(library_presenter.comics.length).to eq(1)
116
+ expect(library_presenter.comics.all? { |bp| bp.is_a?(described_class) }).to be_truthy
117
+ expect(library_presenter.comic_ids).to match_array(library.comic_ids)
98
118
  expect(library_presenter).not_to be_real
99
119
  end
100
120
 
101
121
  it 'loads belongs_to reflections' do
102
- expect(book_presenter.library_id).to eq(library.id)
103
- expect(book_presenter.library).to be_a(described_class)
104
- expect(book_presenter.library.model).to eq(library.class)
105
- expect(book_presenter).not_to be_real
122
+ comic.save!
123
+ expect(comic_presenter.library_id).to eq(library.id)
124
+ expect(comic_presenter.library).to be_a(described_class)
125
+ expect(comic_presenter.library.model).to eq(library.class)
126
+ expect(comic_presenter.comic_shop_id).to eq(comic_shop.id)
127
+ expect(comic_presenter.comic_shop).to be_a(described_class)
128
+ expect(comic_presenter.comic_shop.model).to eq(comic_shop.class)
129
+ expect(comic_presenter).not_to be_real
106
130
  end
107
131
 
108
132
  context 'missing parent id' do
@@ -129,15 +153,22 @@ describe SpeedyAF::Base do
129
153
 
130
154
  it 'has already loaded has_many reflections' do
131
155
  library.books.create(title: 'Ordered Things II')
156
+ library.comics.create(title: 'Comet in Moominland')
132
157
  library.save
133
158
  book_ids = library.book_ids
159
+ comic_ids = library.comic_ids
134
160
  library_presenter = described_class.find(library.id, load_reflections: true)
135
161
  expect(library_presenter.attrs).to include :books
162
+ expect(library_presenter.attrs).to include :comics
136
163
  allow(ActiveFedora::SolrService).to receive(:query).and_call_original
137
- presenter = library_presenter.books
138
- expect(presenter.length).to eq(2)
139
- expect(presenter.all? { |bp| bp.is_a?(described_class) }).to be_truthy
164
+ books_presenter = library_presenter.books
165
+ comics_presenter = library_presenter.comics
166
+ expect(books_presenter.length).to eq(2)
167
+ expect(books_presenter.all? { |bp| bp.is_a?(described_class) }).to be_truthy
168
+ expect(comics_presenter.length).to eq(1)
169
+ expect(comics_presenter.all? { |bp| bp.is_a?(described_class) }).to be_truthy
140
170
  expect(library_presenter.book_ids).to match_array(book_ids)
171
+ expect(library_presenter.comic_ids).to match_array(comic_ids)
141
172
  expect(library_presenter).not_to be_real
142
173
  expect(ActiveFedora::SolrService).not_to have_received(:query)
143
174
  end
@@ -151,13 +182,61 @@ describe SpeedyAF::Base do
151
182
  expect(book_presenter).not_to be_real
152
183
  expect(ActiveFedora::SolrService).not_to have_received(:query)
153
184
  end
185
+
186
+ context 'filtering' do
187
+ let(:book_presenter) { described_class.find(book.id, load_reflections: [:indexed_file]) }
188
+ let(:comic_presenter) { described_class.find(comic.id, load_reflections: [:comic_shop]) }
189
+ before { comic.save! }
190
+
191
+ it 'has already loaded filtered subresources' do
192
+ expect(book_presenter.attrs).to include :indexed_file
193
+ expect(book_presenter.attrs).to_not include :descMetadata
194
+ allow(ActiveFedora::SolrService).to receive(:query).and_call_original
195
+ ipsum_presenter = book_presenter.indexed_file
196
+ expect(ipsum_presenter.model).to eq(IndexedFile)
197
+ expect(ipsum_presenter.content).to eq(indexed_content)
198
+ expect(ipsum_presenter).not_to be_real
199
+ expect(ActiveFedora::SolrService).not_to have_received(:query)
200
+ end
201
+
202
+ it 'has already loaded filtered has_many reflections' do
203
+ library.books.create(title: 'Ordered Things II')
204
+ library.save
205
+ book_ids = library.book_ids
206
+ library_presenter = described_class.find(library.id, load_reflections: [:books])
207
+ expect(library_presenter.attrs).to include :books
208
+ expect(library_presenter.attrs).to_not include :comics
209
+ allow(ActiveFedora::SolrService).to receive(:query).and_call_original
210
+ presenter = library_presenter.books
211
+ expect(presenter.length).to eq(2)
212
+ expect(presenter.all? { |bp| bp.is_a?(described_class) }).to be_truthy
213
+ expect(library_presenter.book_ids).to match_array(book_ids)
214
+ expect(library_presenter).not_to be_real
215
+ expect(ActiveFedora::SolrService).not_to have_received(:query)
216
+ end
217
+
218
+ it 'has already loaded belongs_to reflections and does not filter' do
219
+ expect(comic_presenter.attrs).to include :comic_shop
220
+ expect(comic_presenter.attrs).to include :library
221
+ allow(ActiveFedora::SolrService).to receive(:query).and_call_original
222
+ expect(comic_presenter.comic_shop_id).to eq(comic_shop.id)
223
+ expect(comic_presenter.comic_shop).to be_a(described_class)
224
+ expect(comic_presenter.comic_shop.model).to eq(comic_shop.class)
225
+ expect(comic_presenter).not_to be_real
226
+ expect(comic_presenter.library_id).to eq(library.id)
227
+ expect(comic_presenter.library).to be_a(described_class)
228
+ expect(comic_presenter.library.model).to eq(library.class)
229
+ expect(comic_presenter).not_to be_real
230
+ expect(ActiveFedora::SolrService).not_to have_received(:query)
231
+ end
232
+ end
154
233
  end
155
234
  end
156
235
 
157
236
  context 'configuration' do
158
237
  before do
159
238
  described_class.config Book do
160
- include DowncaseBehavior
239
+ include TitleBehavior
161
240
  self.defaults = { foo: 'bar!' }
162
241
  end
163
242