oai 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.md +28 -23
  2. data/Rakefile +14 -40
  3. data/examples/providers/dublin_core.rb +63 -63
  4. data/lib/oai/client.rb +131 -97
  5. data/lib/oai/client/list_identifiers.rb +1 -0
  6. data/lib/oai/client/list_records.rb +6 -5
  7. data/lib/oai/client/list_sets.rb +6 -5
  8. data/lib/oai/client/record.rb +6 -7
  9. data/lib/oai/client/response.rb +7 -4
  10. data/lib/oai/client/resumable.rb +42 -0
  11. data/lib/oai/harvester/shell.rb +40 -41
  12. data/lib/oai/provider.rb +85 -67
  13. data/lib/oai/provider/metadata_format/oai_dc.rb +5 -6
  14. data/lib/oai/provider/model/activerecord_caching_wrapper.rb +23 -25
  15. data/lib/oai/provider/model/activerecord_wrapper.rb +99 -51
  16. data/lib/oai/provider/response.rb +33 -31
  17. data/lib/oai/provider/response/get_record.rb +7 -7
  18. data/lib/oai/provider/response/list_records.rb +5 -4
  19. data/lib/oai/provider/response/record_response.rb +14 -14
  20. data/test/activerecord_provider/config/connection.rb +8 -4
  21. data/test/activerecord_provider/database/{ar_migration.rb → 0001_oaipmh_tables.rb} +17 -12
  22. data/test/activerecord_provider/helpers/providers.rb +2 -3
  23. data/test/activerecord_provider/helpers/set_provider.rb +10 -22
  24. data/test/activerecord_provider/helpers/transactional_test_case.rb +34 -0
  25. data/test/activerecord_provider/models/dc_field.rb +4 -4
  26. data/test/activerecord_provider/models/dc_set.rb +3 -2
  27. data/test/activerecord_provider/models/exclusive_set_dc_field.rb +11 -0
  28. data/test/activerecord_provider/tc_ar_provider.rb +67 -28
  29. data/test/activerecord_provider/tc_ar_sets_provider.rb +104 -18
  30. data/test/activerecord_provider/tc_caching_paging_provider.rb +6 -10
  31. data/test/activerecord_provider/tc_simple_paging_provider.rb +7 -11
  32. data/test/activerecord_provider/test_helper.rb +10 -0
  33. data/test/client/helpers/provider.rb +44 -47
  34. data/test/client/helpers/test_wrapper.rb +4 -16
  35. data/test/client/tc_http_client.rb +90 -2
  36. data/test/client/tc_list_identifiers.rb +22 -3
  37. data/test/client/tc_list_records.rb +17 -4
  38. data/test/client/tc_list_sets.rb +17 -2
  39. data/test/provider/models.rb +32 -30
  40. data/test/provider/tc_exceptions.rb +30 -20
  41. data/test/provider/tc_functional_tokens.rb +11 -6
  42. data/test/provider/tc_provider.rb +58 -24
  43. data/test/provider/tc_resumption_tokens.rb +6 -6
  44. data/test/provider/tc_simple_provider.rb +51 -26
  45. data/test/provider/test_helper.rb +7 -0
  46. metadata +67 -128
  47. data/test/activerecord_provider/config/database.yml +0 -6
  48. data/test/activerecord_provider/database/oaipmhtest +0 -0
data/README.md CHANGED
@@ -2,15 +2,17 @@ ruby-oai
2
2
  ========
3
3
 
4
4
  ruby-oai is a Open Archives Protocol for Metadata Harvesting (OAI-PMH)
5
- library for Ruby. OAI-PMH[http://openarchives.org] it is a somewhat
5
+ library for Ruby. [OAI-PMH](http://openarchives.org) is a somewhat
6
6
  archaic protocol for sharing metadata between digital library repositories.
7
7
  If you are looking to share metadata on the web you are probably better off
8
- using a feed format like RSS or Atom. If have to work with a backwards
8
+ using a feed format like [RSS](http://www.rssboard.org/rss-specification) or
9
+ [Atom](http://www.atomenabled.org/). If have to work with a backwards
9
10
  digital repository that only offers OAI-PMH access then ruby-oai is your
10
11
  friend.
11
12
 
12
- The [OAI-PMH](http://openarchives.org) spec defines six verbs (Identify, ListIdentifiers, ListRecords,
13
- GetRecords, ListSets, ListMetadataFormat) used for discovery and sharing of
13
+ The [OAI-PMH](http://openarchives.org) spec defines six verbs
14
+ (`Identify`, `ListIdentifiers`, `ListRecords`,
15
+ `GetRecords`, `ListSets`, `ListMetadataFormat`) used for discovery and sharing of
14
16
  metadata.
15
17
 
16
18
  The ruby-oai gem includes a client library, a server/provider library and
@@ -25,12 +27,23 @@ For example to initiate a ListRecords request to pubmed you can:
25
27
  ```ruby
26
28
  require 'oai'
27
29
  client = OAI::Client.new 'http://www.pubmedcentral.gov/oai/oai.cgi'
28
- for record in client.list_records
30
+ response = client.list_records
31
+ # Get the first page of records
32
+ response.each do |record|
33
+ puts record.metadata
34
+ end
35
+ # Get the second page of records
36
+ response = client.list_records(:resumption_token => response.resumption_token)
37
+ response.each do |record|
38
+ puts record.metadata
39
+ end
40
+ # Get all pages together (may take a *very* long time to complete)
41
+ client.list_records.full.each do |record|
29
42
  puts record.metadata
30
43
  end
31
44
  ```
32
45
 
33
- See OAI::Client for more details
46
+ See {OAI::Client} for more details
34
47
 
35
48
  Server
36
49
  ------
@@ -47,36 +60,28 @@ The OAI provider library handles serving local content to other clients. Here's
47
60
  end
48
61
  ```
49
62
 
50
- See OAI::Provider for more details
63
+ See {OAI::Provider} for more details
51
64
 
52
65
  Interactive Harvester
53
66
  ---------------------
54
67
 
55
- The OAI-PMH client shell allows OAI Harvesting to be configured in an interactive manner. Typing 'oai' on the command line starts the shell. After initial configuration, the shell can be used to manage harvesting operations.
68
+ The OAI-PMH client shell allows OAI Harvesting to be configured in an interactive manner. Typing `oai` on the command line starts the shell. After initial configuration, the shell can be used to manage harvesting operations.
56
69
 
57
- See OAI::Harvester::Shell for more details
70
+ See {OAI::Harvester::Shell} for more details
58
71
 
59
72
  Installation
60
73
  ------------
61
74
 
62
- Normally the best way to install oai is from rubyforge using the gem
63
- command line tool:
75
+ Normally the best way to install oai is as part of your `Gemfile`:
64
76
 
65
- ```
66
- % gem install oai
67
- ```
68
-
69
- If you're reading this you've presumably got the tarball or zip distribution.
70
- So you'll need to:
77
+ source :rubygems
78
+ gem 'oai'
71
79
 
72
- ```
73
- % rake package
74
- % gem install pkg/oai-x.y.z.gem
75
- ```
80
+ Alternately it can be installed globally using RubyGems:
76
81
 
77
- Where x.y.z is the version of the gem that was generated.
82
+ $ gem install oai
78
83
 
79
84
  License
80
85
  -------
81
86
 
82
- [Public Domain](http://creativecommons.org/publicdomain/zero/1.0/)
87
+ [![CC0 - Public Domain](http://i.creativecommons.org/p/zero/1.0/88x15.png)](http://creativecommons.org/publicdomain/zero/1.0/)
data/Rakefile CHANGED
@@ -10,11 +10,11 @@ end
10
10
  Bundler::GemHelper.install_tasks
11
11
 
12
12
  require 'rake/testtask'
13
- require 'rdoc/task'
13
+ require 'yard'
14
14
 
15
- task :default => ["test"]
15
+ task :default => ["test", "yard"]
16
16
 
17
- task :test => ["test:client", "test:provider"]
17
+ task :test => ["test:client", "test:provider", "test:activerecord_provider"]
18
18
 
19
19
  namespace :test do
20
20
  Rake::TestTask.new('client') do |t|
@@ -44,10 +44,12 @@ namespace :test do
44
44
  if RUBY_VERSION =~ /^1.8/
45
45
  Rake::Task['rcov:client'].invoke
46
46
  Rake::Task['rcov:provider'].invoke
47
+ Rake::Task['rcov:activerecord_provider'].invoke
47
48
  else
48
49
  ENV['COVERAGE'] = 'true'
49
50
  Rake::Task['test:client'].invoke
50
51
  Rake::Task['test:provider'].invoke
52
+ Rake::Task['test:activerecord_provider'].invoke
51
53
  end
52
54
 
53
55
  system("open coverage/index.html") if (PLATFORM['darwin'] if Kernel.const_defined? :PLATFORM) || (RUBY_PLATFORM =~ /darwin/ if Kernel.const_defined? :RUBY_PLATFORM)
@@ -72,45 +74,17 @@ if RUBY_VERSION =~ /^1.8/
72
74
  t.verbose = true
73
75
  t.rcov_opts = ['--aggregate coverage.data', '--text-summary']
74
76
  end
75
- end
76
- end
77
77
 
78
- task 'test:activerecord_provider' => :create_database
79
-
80
- task :environment do
81
- unless defined? OAI_PATH
82
- OAI_PATH = File.dirname(__FILE__) + '/lib/oai'
83
- $LOAD_PATH << OAI_PATH
84
- $LOAD_PATH << File.dirname(__FILE__) + '/test'
85
- end
86
- end
87
-
88
- task :drop_database => :environment do
89
- %w{rubygems active_record yaml}.each { |lib| require lib }
90
- require 'activerecord_provider/database/ar_migration'
91
- require 'activerecord_provider/config/connection'
92
- begin
93
- OAIPMHTables.down
94
- rescue
78
+ Rcov::RcovTask.new('activerecord_provider') do |t|
79
+ t.libs << ['lib', 'test/activerecord_provider']
80
+ t.pattern = 'test/activerecord_provider/tc_*.rb'
81
+ t.verbose = true
82
+ t.rcov_opts = ['--aggregate coverage.data', '--text-summary']
83
+ end
95
84
  end
96
85
  end
97
86
 
98
- task :create_database => :drop_database do
99
- OAIPMHTables.up
100
- end
101
-
102
- task :load_fixtures => :create_database do
103
- require 'test/activerecord_provider/models/dc_field'
104
- fixtures = YAML.load_file(
105
- File.join('test', 'activerecord_provider', 'fixtures', 'dc.yml')
106
- )
107
- fixtures.keys.sort.each do |key|
108
- DCField.create(fixtures[key])
109
- end
110
- end
111
-
112
- Rake::RDocTask.new('doc') do |rd|
113
- rd.rdoc_files.include("lib/**/*.rb", "README.md")
114
- rd.main = 'README.md'
115
- rd.rdoc_dir = 'doc'
87
+ YARD::Rake::YardocTask.new do |t|
88
+ t.files = ["lib/**/*.rb"]
89
+ t.options = ['--output-dir', 'doc']
116
90
  end
@@ -4,7 +4,7 @@ require 'camping/session'
4
4
  require 'oai/provider'
5
5
 
6
6
  # Extremely simple demo Camping application to illustrate OAI Provider integration
7
- # with Camping.
7
+ # with Camping.
8
8
  #
9
9
  # William Groppe 2/1/2007
10
10
  #
@@ -13,9 +13,9 @@ Camping.goes :DublinCore
13
13
 
14
14
  module DublinCore
15
15
  include Camping::Session
16
-
17
- FIELDS = ['title', 'creator', 'subject', 'description',
18
- 'publisher', 'contributor', 'date', 'type', 'format',
16
+
17
+ FIELDS = ['title', 'creator', 'subject', 'description',
18
+ 'publisher', 'contributor', 'date', 'type', 'format',
19
19
  'identifier', 'source', 'language', 'relation', 'coverage', 'rights']
20
20
 
21
21
  def DublinCore.create
@@ -23,7 +23,7 @@ module DublinCore
23
23
  DublinCore::Models.create_schema :assume =>
24
24
  (DublinCore::Models::Obj.table_exists? ? 1.0 : 0.0)
25
25
  end
26
-
26
+
27
27
  end
28
28
 
29
29
  module DublinCore::Models
@@ -32,7 +32,7 @@ module DublinCore::Models
32
32
  Base.default_timezone = :utc
33
33
 
34
34
  class Obj < Base # since Object is reserved
35
- has_and_belongs_to_many :fields, :join_table => 'dublincore_field_links',
35
+ has_and_belongs_to_many :fields, :join_table => 'dublincore_field_links',
36
36
  :foreign_key => 'obj_id', :association_foreign_key => 'field_id'
37
37
  DublinCore::FIELDS.each do |field|
38
38
  class_eval(%{
@@ -44,68 +44,68 @@ module DublinCore::Models
44
44
  });
45
45
  end
46
46
  end
47
-
47
+
48
48
  class Field < Base
49
- has_and_belongs_to_many :objs, :join_table => 'dublincore_field_links',
49
+ has_and_belongs_to_many :objs, :join_table => 'dublincore_field_links',
50
50
  :foreign_key => 'field_id', :association_foreign_key => 'obj_id'
51
51
  validates_presence_of :field_type, :message => "can't be blank"
52
-
52
+
53
53
  # Support sorting by value
54
54
  def <=>(other)
55
55
  self.to_s <=> other.to_s
56
56
  end
57
-
57
+
58
58
  def to_s
59
59
  value
60
60
  end
61
61
  end
62
-
62
+
63
63
  DublinCore::FIELDS.each do |field|
64
64
  module_eval(%{
65
65
  class DC#{field.capitalize} < Field; end
66
66
  })
67
67
  end
68
-
68
+
69
69
  # OAI Provider configuration
70
70
  class CampingProvider < OAI::Provider::Base
71
71
  repository_name 'Camping Test OAI Repository'
72
72
  source_model ActiveRecordWrapper.new(Obj)
73
73
  end
74
-
74
+
75
75
  class CreateTheBasics < V 1.0
76
76
  def self.up
77
77
  create_table :dublincore_objs, :force => true do |t|
78
78
  t.column :source, :string
79
79
  t.column :created_at, :datetime
80
80
  t.column :updated_at, :datetime
81
- end
82
-
81
+ end
82
+
83
83
  create_table :dublincore_field_links, :id => false, :force => true do |t|
84
84
  t.column :obj_id, :integer, :null => false
85
85
  t.column :field_id, :integer, :null => false
86
86
  end
87
-
87
+
88
88
  create_table :dublincore_fields, :force => true do |t|
89
89
  t.column :field_type, :string, :limit => 30, :null => false
90
90
  t.column :value, :text, :null => false
91
91
  end
92
-
92
+
93
93
  add_index :dublincore_fields, [:field_type, :value], :uniq => true
94
94
  add_index :dublincore_field_links, :field_id
95
95
  add_index :dublincore_field_links, [:obj_id, :field_id]
96
96
  end
97
-
97
+
98
98
  def self.down
99
99
  drop_table :dublincore_objs
100
100
  drop_table :dublincore_field_links
101
101
  drop_table :dublincore_fields
102
102
  end
103
103
  end
104
-
104
+
105
105
  end
106
106
 
107
107
  module DublinCore::Controllers
108
-
108
+
109
109
  # Now setup a URL('/oai' by default) to handle OAI requests
110
110
  class Oai
111
111
  def get
@@ -114,13 +114,13 @@ module DublinCore::Controllers
114
114
  provider.process_request(@input.merge(:url => "http:"+URL(Oai).to_s))
115
115
  end
116
116
  end
117
-
117
+
118
118
  class Index < R '/', '/browse/(\w+)', '/browse/(\w+)/page/(\d+)'
119
119
  def get(field = nil, page = 1)
120
120
  @field = field
121
121
  @page = page.to_i
122
122
  @browse = {}
123
- if !@field
123
+ if !@field
124
124
  FIELDS.each do |field|
125
125
  @browse[field] = Field.count(
126
126
  :conditions => ["field_type = ?", "DC#{field.capitalize}"])
@@ -129,11 +129,11 @@ module DublinCore::Controllers
129
129
  @count = @browse.keys.size
130
130
  else
131
131
  @count = Field.count(:conditions => ["field_type = ?", "DC#{@field.capitalize}"])
132
- fields = Field.find(:all,
132
+ fields = Field.find(:all,
133
133
  :conditions => ["field_type = ?", "DC#{@field.capitalize}"],
134
- :order => "value asc", :limit => DublinCore::LIMIT,
134
+ :order => "value asc", :limit => DublinCore::LIMIT,
135
135
  :offset => (@page - 1) * DublinCore::LIMIT)
136
-
136
+
137
137
  fields.each do |field|
138
138
  @browse[field] = field.objs.size
139
139
  end
@@ -141,14 +141,14 @@ module DublinCore::Controllers
141
141
  render :browse
142
142
  end
143
143
  end
144
-
144
+
145
145
  class Search < R '/search', '/search/page/(\d+)'
146
-
146
+
147
147
  def get(page = 1)
148
148
  @page = page.to_i
149
149
  if input.terms
150
150
  @state.terms = input.terms if input.terms
151
-
151
+
152
152
  start = Time.now
153
153
  ids = search(input.terms, @page - 1)
154
154
  finish = Time.now
@@ -158,31 +158,31 @@ module DublinCore::Controllers
158
158
  @count = 0
159
159
  @objs = []
160
160
  end
161
-
161
+
162
162
  render :search
163
163
  end
164
-
164
+
165
165
  end
166
-
166
+
167
167
  class LinkedTo < R '/linked/(\d+)', '/linked/(\d+)/page/(\d+)'
168
168
  def get(field, page = 1)
169
169
  @page = page.to_i
170
170
  @field = field
171
171
  @count = Field.find(field).objs.size
172
- @objs = Field.find(field).objs.find(:all,
173
- :limit => DublinCore::LIMIT,
172
+ @objs = Field.find(field).objs.find(:all,
173
+ :limit => DublinCore::LIMIT,
174
174
  :offset => (@page - 1) * DublinCore::LIMIT)
175
175
  render :records
176
176
  end
177
177
  end
178
-
178
+
179
179
  class Add
180
180
  def get
181
181
  @obj = Obj.create
182
182
  render :edit
183
183
  end
184
184
  end
185
-
185
+
186
186
  class View < R '/view/(\d+)'
187
187
  def get obj_id
188
188
  obj = Obj.find(obj_id)
@@ -198,13 +198,13 @@ module DublinCore::Controllers
198
198
  end
199
199
  end
200
200
  end
201
-
201
+
202
202
  class Edit < R '/edit', '/edit/(\d+)'
203
203
  def get obj_id
204
204
  @obj = Obj.find obj_id
205
205
  render :edit
206
206
  end
207
-
207
+
208
208
  def post
209
209
  case input.action
210
210
  when 'Save'
@@ -220,10 +220,10 @@ module DublinCore::Controllers
220
220
  redirect View, @obj
221
221
  when 'Discard'
222
222
  @obj = Obj.find input.obj_id
223
-
223
+
224
224
  # Get rid of completely empty records
225
225
  @obj.destroy if @obj.fields.empty?
226
-
226
+
227
227
  if Obj.exists?(@obj.id)
228
228
  redirect View, @obj
229
229
  else
@@ -235,7 +235,7 @@ module DublinCore::Controllers
235
235
  end
236
236
  end
237
237
  end
238
-
238
+
239
239
  class DataAdd < R '/data/add'
240
240
  def post
241
241
  if input.field_value && !input.field_value.empty?
@@ -246,7 +246,7 @@ module DublinCore::Controllers
246
246
  redirect Edit, input.obj_id
247
247
  end
248
248
  end
249
-
249
+
250
250
  class Style < R '/styles.css'
251
251
  def get
252
252
  @headers["Content-Type"] = "text/css; charset=utf-8"
@@ -266,7 +266,7 @@ module DublinCore::Controllers
266
266
  .totals { font-size: 60%; margin-left: .25em; vertical-align: super; }
267
267
  .field_labels { font-size: 60%; margin-left: 1em; vertical-align: super; }
268
268
  h2 {color: #CC6600; padding: 0; margin-bottom: .15em; font-size: 160%;}
269
- h3.header { padding:0; margin:0; position: relative; top: -2.8em;
269
+ h3.header { padding:0; margin:0; position: relative; top: -2.8em;
270
270
  padding-bottom: .25em; padding-right: 5em; font-size: 80%; }
271
271
  h1.header a { color: #FF9900; text-decoration: none;
272
272
  font: bold 250% "Trebuchet MS",Trebuchet,Georgia, Serif;
@@ -294,7 +294,7 @@ module DublinCore::Controllers
294
294
  end
295
295
 
296
296
  module DublinCore::Helpers
297
-
297
+
298
298
  def paginate(klass, term = nil)
299
299
  @total_pages = count/DublinCore::LIMIT + 1
300
300
  div.pagination do
@@ -310,14 +310,14 @@ module DublinCore::Helpers
310
310
  end
311
311
  end
312
312
  end
313
-
313
+
314
314
  private
315
-
315
+
316
316
  def link_if(string, klass, term, page)
317
317
  return "#{string} " if (@page == page || 1 > page || page > @total_pages)
318
318
  a(string, :href => term.nil? ? R(klass, page) : R(klass, term, page)) << " "
319
319
  end
320
-
320
+
321
321
  def page_window
322
322
  return 1..@total_pages if @total_pages < 9
323
323
  size = @total_pages > 9 ? 9 : @total_pages
@@ -325,11 +325,11 @@ module DublinCore::Helpers
325
325
  start = @total_pages - size if start+size > @total_pages
326
326
  start..start+size
327
327
  end
328
-
328
+
329
329
  end
330
330
 
331
331
  module DublinCore::Views
332
-
332
+
333
333
  def layout
334
334
  html do
335
335
  head do
@@ -353,7 +353,7 @@ module DublinCore::Views
353
353
  end
354
354
  end
355
355
  end
356
-
356
+
357
357
  def browse
358
358
  if @browse.empty?
359
359
  p 'No objects found, try adding one.'
@@ -367,17 +367,17 @@ module DublinCore::Views
367
367
  paginate(Index, @field) if @count > DublinCore::LIMIT
368
368
  end
369
369
  end
370
-
370
+
371
371
  def delete_success
372
372
  p "Delete was successful"
373
373
  end
374
-
374
+
375
375
  def search
376
376
  p.results { span "#{count} results for '#{@state.terms}'"; span.tiny "(#{@search_time} secs)" }
377
377
  ul.undecorated do
378
378
  @result.keys.sort.each do |record|
379
379
  li do
380
- a(record.value, :href => R(LinkedTo, record.id))
380
+ a(record.value, :href => R(LinkedTo, record.id))
381
381
  span.totals "(#{@result[record]})"
382
382
  span.field_labels "#{record.field_type.sub(/^DC/, '').downcase} "
383
383
  end
@@ -385,20 +385,20 @@ module DublinCore::Views
385
385
  end
386
386
  paginate(Search) if @count > DublinCore::LIMIT
387
387
  end
388
-
388
+
389
389
  def edit
390
390
  h3 "Editing Record"
391
391
  p "To remove a field entry, just remove it's content."
392
392
  _form(@obj, :action => R(Edit, @obj))
393
393
  end
394
-
394
+
395
395
  def records
396
396
  @objs.each { |obj| _obj(obj) }
397
397
  paginate(LinkedTo, @field) if @count > DublinCore::LIMIT
398
398
  end
399
-
399
+
400
400
  def _obj(obj, edit = false)
401
- table.obj :cellspacing => 0 do
401
+ table.obj(:cellspacing => 0) do
402
402
  _edit_controls(obj, edit)
403
403
  DublinCore::FIELDS.each do |field|
404
404
  obj.send(field.pluralize.intern).each_with_index do |value, index|
@@ -406,8 +406,8 @@ module DublinCore::Views
406
406
  td.label { 0 == index ? "#{field}(s)" : "&nbsp;" }
407
407
  if edit
408
408
  td.value do
409
- input :name => value.class,
410
- :type => 'text',
409
+ input :name => value.class,
410
+ :type => 'text',
411
411
  :value => value.to_s
412
412
  end
413
413
  else
@@ -418,7 +418,7 @@ module DublinCore::Views
418
418
  end
419
419
  end
420
420
  end
421
-
421
+
422
422
  def _form(obj, action)
423
423
  form.controls(:method => 'post', :action => R(Edit)) do
424
424
  input :type => 'hidden', :name => 'obj_id', :value => obj.id
@@ -446,7 +446,7 @@ module DublinCore::Views
446
446
  end
447
447
  end
448
448
  end
449
-
449
+
450
450
  def _edit_controls(obj, edit)
451
451
  tr.controls do
452
452
  td :colspan => 2 do
@@ -455,8 +455,8 @@ module DublinCore::Views
455
455
  end
456
456
  end
457
457
  end
458
-
459
-
458
+
459
+
460
460
  def _key_value(key, value)
461
461
  if value > 0
462
462
  if key.kind_of?(DublinCore::Models::Field)
@@ -470,5 +470,5 @@ module DublinCore::Views
470
470
  span.totals "(#{value})"
471
471
  end
472
472
  end
473
-
473
+
474
474
  end