active-fedora 4.5.3 → 4.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.add_dependency('solrizer', '~>1.2.0')
21
21
  s.add_dependency("activeresource", '>= 3.0.0')
22
22
  s.add_dependency("activesupport", '>= 3.0.0')
23
+ s.add_dependency("builder", '~> 3.0.0')
23
24
  s.add_dependency("mediashelf-loggable")
24
25
  s.add_dependency("equivalent-xml")
25
26
  s.add_dependency("rubydora", '~>0.5.13')
@@ -22,6 +22,7 @@ module ActiveFedora #:nodoc:
22
22
 
23
23
  eager_autoload do
24
24
  autoload :Associations
25
+ autoload :Attributes
25
26
  autoload :Base
26
27
  autoload :ContentModel
27
28
  autoload :Callbacks
@@ -35,7 +35,7 @@ module ActiveFedora
35
35
  # ActiveFedora::Associations::HasManyAssociation.
36
36
 
37
37
  class AssociationProxy
38
- delegate :to_param, :to=>:target
38
+ #delegate :to_param, :to=>:target
39
39
  instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
40
40
 
41
41
  def initialize(owner, reflection)
@@ -0,0 +1,82 @@
1
+ module ActiveFedora
2
+ module Attributes
3
+ extend ActiveSupport::Concern
4
+ extend ActiveSupport::Autoload
5
+ autoload :Serializers
6
+
7
+ included do
8
+ include Serializers
9
+ end
10
+
11
+ def attributes=(properties)
12
+ properties.each do |k, v|
13
+ respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise(UnknownAttributeError, "unknown attribute: #{k}")
14
+ end
15
+ end
16
+
17
+
18
+ # A convenience method for updating indexed attributes. The passed in hash
19
+ # must look like this :
20
+ # {{:name=>{"0"=>"a","1"=>"b"}}
21
+ #
22
+ # This will result in any datastream field of name :name having the value [a,b]
23
+ #
24
+ # An index of -1 will insert a new value. any existing value at the relevant index
25
+ # will be overwritten.
26
+ #
27
+ # As in update_attributes, this overwrites _all_ available fields by default.
28
+ #
29
+ # If you want to specify which datastream(s) to update,
30
+ # use the :datastreams argument like so:
31
+ # m.update_attributes({"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}, :datastreams=>"my_ds")
32
+ # or
33
+ # m.update_attributes({"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}, :datastreams=>["my_ds", "my_other_ds"])
34
+ #
35
+ def update_indexed_attributes(params={}, opts={})
36
+ if ds = opts[:datastreams]
37
+ ds_array = []
38
+ ds = [ds] unless ds.respond_to? :each
39
+ ds.each do |dsname|
40
+ ds_array << datastreams[dsname]
41
+ end
42
+ else
43
+ ds_array = metadata_streams
44
+ end
45
+ result = {}
46
+ ds_array.each do |d|
47
+ result[d.dsid] = d.update_indexed_attributes(params,opts)
48
+ end
49
+ return result
50
+ end
51
+
52
+ # Updates the attributes for each datastream named in the params Hash
53
+ # @param [Hash] params A Hash whose keys correspond to datastream ids and whose values are appropriate Hashes to submit to update_indexed_attributes on that datastream
54
+ # @param [Hash] opts (currently ignored.)
55
+ # @example Update the descMetadata and properties datastreams with new values
56
+ # article = HydrangeaArticle.new
57
+ # ds_values_hash = {
58
+ # "descMetadata"=>{ [{:person=>0}, :role]=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"} },
59
+ # "properties"=>{ "notes"=>"foo" }
60
+ # }
61
+ # article.update_datastream_attributes( ds_values_hash )
62
+ def update_datastream_attributes(params={}, opts={})
63
+ result = params.dup
64
+ params.each_pair do |dsid, ds_params|
65
+ if datastreams.include?(dsid)
66
+ result[dsid] = datastreams[dsid].update_indexed_attributes(ds_params)
67
+ else
68
+ result.delete(dsid)
69
+ end
70
+ end
71
+ return result
72
+ end
73
+
74
+ def get_values_from_datastream(dsid,field_key,default=[])
75
+ if datastreams.include?(dsid)
76
+ return datastreams[dsid].get_values(field_key,default)
77
+ else
78
+ return nil
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,74 @@
1
+ module ActiveFedora
2
+ module Attributes
3
+ module Serializers
4
+ extend ActiveSupport::Concern
5
+
6
+ ## This allows you to use date_select helpers in rails views
7
+ # @param [Hash] parms parameters hash
8
+ # @return [Hash] a parameters list with the date select parameters replaced with dates
9
+ def deserialize_dates_from_form(params)
10
+ dates = {}
11
+ params.each do |key, value|
12
+ if data = key.to_s.match(/^(.+)\((\d)i\)$/)
13
+ dates[data[1]] ||= {}
14
+ dates[data[1]][data[2]] = value
15
+ params.delete(key)
16
+ end
17
+ end
18
+ dates.each do |key, value|
19
+ params[key] = [value['1'], value['2'], value['3']].join('-')
20
+ end
21
+ params
22
+ end
23
+
24
+ # set a hash of attributes on the object
25
+ # @param [Hash] params the properties to set on the object
26
+ def attributes=(params)
27
+ super(deserialize_dates_from_form(params))
28
+ end
29
+
30
+ module ClassMethods
31
+ # @param [String] value a string to be cast to integer
32
+ # @param [Hash] options
33
+ # @option options [Integer] :default a value to return if the passed value argument is blank
34
+ # @return [Integer]
35
+ def coerce_to_integer(value, options={})
36
+ if value.blank?
37
+ options[:default] || nil
38
+ else
39
+ value.to_i
40
+ end
41
+ end
42
+
43
+ # @param [String] value a string to be cast to boolean
44
+ # @param [Hash] options
45
+ # @option options [Boolean] :default a value to return if the passed value argument is blank
46
+ # @return [Boolean] true if value == "true" or default if value is blank
47
+ def coerce_to_boolean(value, options={})
48
+ if value.blank?
49
+ options[:default] || nil
50
+ else
51
+ value=="true"
52
+ end
53
+ end
54
+
55
+ # @param [String] value a string to be cast to boolean
56
+ # @param [Hash] options
57
+ # @option options [Boolean] :default a value to return if the passed value argument is blank
58
+ # @return [Boolean] true if value == "true" or default if value is blank
59
+ def coerce_to_date(v, options={})
60
+ if v.blank? && options[:default]
61
+ options[:default] == :today ? Date.today : options[:default]
62
+ else
63
+ begin
64
+ Date.parse(v)
65
+ rescue TypeError, ArgumentError
66
+ nil
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -61,11 +61,6 @@ module ActiveFedora
61
61
  !new_object?
62
62
  end
63
63
 
64
- def attributes=(properties)
65
- properties.each do |k, v|
66
- respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise(UnknownAttributeError, "unknown attribute: #{k}")
67
- end
68
- end
69
64
 
70
65
  # Constructor. You may supply a custom +:pid+, or we call the Fedora Rest API for the
71
66
  # next available Fedora pid, and mark as new object.
@@ -207,6 +202,10 @@ module ActiveFedora
207
202
  self.pid
208
203
  end
209
204
 
205
+ def to_param
206
+ persisted? ? to_key.join('-') : nil
207
+ end
208
+
210
209
  def to_key
211
210
  persisted? ? [pid] : nil
212
211
  end
@@ -420,70 +419,6 @@ module ActiveFedora
420
419
  obj.inner_object.freeze
421
420
  obj
422
421
  end
423
-
424
- # A convenience method for updating indexed attributes. The passed in hash
425
- # must look like this :
426
- # {{:name=>{"0"=>"a","1"=>"b"}}
427
- #
428
- # This will result in any datastream field of name :name having the value [a,b]
429
- #
430
- # An index of -1 will insert a new value. any existing value at the relevant index
431
- # will be overwritten.
432
- #
433
- # As in update_attributes, this overwrites _all_ available fields by default.
434
- #
435
- # If you want to specify which datastream(s) to update,
436
- # use the :datastreams argument like so:
437
- # m.update_attributes({"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}, :datastreams=>"my_ds")
438
- # or
439
- # m.update_attributes({"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}, :datastreams=>["my_ds", "my_other_ds"])
440
- #
441
- def update_indexed_attributes(params={}, opts={})
442
- if ds = opts[:datastreams]
443
- ds_array = []
444
- ds = [ds] unless ds.respond_to? :each
445
- ds.each do |dsname|
446
- ds_array << datastreams[dsname]
447
- end
448
- else
449
- ds_array = metadata_streams
450
- end
451
- result = {}
452
- ds_array.each do |d|
453
- result[d.dsid] = d.update_indexed_attributes(params,opts)
454
- end
455
- return result
456
- end
457
-
458
- # Updates the attributes for each datastream named in the params Hash
459
- # @param [Hash] params A Hash whose keys correspond to datastream ids and whose values are appropriate Hashes to submit to update_indexed_attributes on that datastream
460
- # @param [Hash] opts (currently ignored.)
461
- # @example Update the descMetadata and properties datastreams with new values
462
- # article = HydrangeaArticle.new
463
- # ds_values_hash = {
464
- # "descMetadata"=>{ [{:person=>0}, :role]=>{"0"=>"role1", "1"=>"role2", "2"=>"role3"} },
465
- # "properties"=>{ "notes"=>"foo" }
466
- # }
467
- # article.update_datastream_attributes( ds_values_hash )
468
- def update_datastream_attributes(params={}, opts={})
469
- result = params.dup
470
- params.each_pair do |dsid, ds_params|
471
- if datastreams.include?(dsid)
472
- result[dsid] = datastreams[dsid].update_indexed_attributes(ds_params)
473
- else
474
- result.delete(dsid)
475
- end
476
- end
477
- return result
478
- end
479
-
480
- def get_values_from_datastream(dsid,field_key,default=[])
481
- if datastreams.include?(dsid)
482
- return datastreams[dsid].get_values(field_key,default)
483
- else
484
- return nil
485
- end
486
- end
487
422
 
488
423
  def self.pids_from_uris(uris)
489
424
  if uris.class == String
@@ -500,6 +435,7 @@ module ActiveFedora
500
435
  end
501
436
 
502
437
  Base.class_eval do
438
+ include Attributes
503
439
  include ActiveFedora::Persistence
504
440
  include Model
505
441
  include Solrizer::FieldNameMapper
@@ -6,6 +6,11 @@ module ActiveFedora
6
6
  # much in the way ActiveRecord does.
7
7
  module Model
8
8
  extend ActiveSupport::Concern
9
+
10
+ included do
11
+ class_attribute :solr_query_handler
12
+ self.solr_query_handler = 'standard'
13
+ end
9
14
 
10
15
  # Takes a Fedora URI for a cModel and returns classname, namespace
11
16
  def self.classname_from_uri(uri)
@@ -131,7 +136,7 @@ module ActiveFedora
131
136
 
132
137
  def find_in_batches conditions, opts={}
133
138
  opts[:q] = create_query(conditions)
134
- opts[:qt] = 'standard'
139
+ opts[:qt] = solr_query_handler
135
140
  #set default sort to created date ascending
136
141
  unless opts.include?(:sort)
137
142
  opts[:sort]=[ActiveFedora::SolrService.solr_name(:system_create,:date)+' asc']
@@ -180,9 +185,9 @@ module ActiveFedora
180
185
  # Get a count of the number of objects from solr
181
186
  # Takes :conditions as an argument
182
187
  def count(args = {})
183
- q = search_model_clause
184
- q << " AND #{args[:conditions]}" if args[:conditions]
185
- SolrService.query(q, :raw=>true, :rows=>0)['response']['numFound']
188
+ q = search_model_clause ? [search_model_clause] : []
189
+ q << "#{args[:conditions]}" if args[:conditions]
190
+ SolrService.query(q.join(' AND '), :raw=>true, :rows=>0)['response']['numFound']
186
191
  end
187
192
 
188
193
  #@deprecated
@@ -218,8 +223,8 @@ module ActiveFedora
218
223
  # Find all ActiveFedora objects for this model that match arguments
219
224
  # passed in by querying Solr. Like find_by_solr this returns a solr result.
220
225
  #
221
- # query_fields a hash of object field names and values to filter on (query_fields must be the solr_field_name for non-MetadataDatastream derived datastreams)
222
- # opts specifies options for the solr query
226
+ # @param query_fields [Hash] field names and values to filter on (query_fields must be the solr_field_name for non-MetadataDatastream derived datastreams)
227
+ # @param opts [Hash] specifies options for the solr query
223
228
  #
224
229
  # options may include:
225
230
  #
@@ -32,11 +32,11 @@ module ActiveFedora
32
32
  module ClassMethods
33
33
  # Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+
34
34
  # so an exception is raised if the record is invalid.
35
- def create!(attributes = nil, options = {}, &block)
35
+ def create!(attributes = nil, &block)
36
36
  if attributes.is_a?(Array)
37
- attributes.collect { |attr| create!(attr, options, &block) }
37
+ attributes.collect { |attr| create!(attr, &block) }
38
38
  else
39
- object = new(attributes, options)
39
+ object = new(attributes)
40
40
  yield(object) if block_given?
41
41
  object.save!
42
42
  object
@@ -1,3 +1,3 @@
1
1
  module ActiveFedora
2
- VERSION = "4.5.3"
2
+ VERSION = "4.6.0.rc1"
3
3
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe "persisting objects" do
4
+ before :all do
5
+ class MockAFBaseRelationship < ActiveFedora::Base
6
+ has_metadata :type=>ActiveFedora::SimpleDatastream, :name=>"foo" do |m|
7
+ m.field "name", :string
8
+ end
9
+ delegate :name, :to=>'foo', :unique=>true
10
+ validates :name, :presence=>true
11
+ end
12
+ end
13
+ after :all do
14
+ Object.send(:remove_const, :MockAFBaseRelationship)
15
+ end
16
+
17
+ describe "#create!" do
18
+ it "should validate" do
19
+ lambda { MockAFBaseRelationship.create!}.should raise_error ActiveFedora::RecordInvalid, "Validation failed: Name can't be blank"
20
+ end
21
+ end
22
+ end
@@ -17,6 +17,19 @@ describe ActiveFedora::Model do
17
17
  Object.send(:remove_const, :SpecModel)
18
18
  end
19
19
 
20
+ describe '.solr_query_handler' do
21
+ after do
22
+ # reset to default
23
+ SpecModel::Basic.solr_query_handler = 'standard'
24
+ end
25
+ it "should have a default" do
26
+ SpecModel::Basic.solr_query_handler.should == 'standard'
27
+ end
28
+ it "should be settable" do
29
+ SpecModel::Basic.solr_query_handler = 'search'
30
+ SpecModel::Basic.solr_query_handler.should == 'search'
31
+ end
32
+ end
20
33
 
21
34
  describe '#find' do
22
35
  describe "without :cast" do
@@ -173,6 +186,12 @@ describe ActiveFedora::Model do
173
186
  ActiveFedora::SolrService.expects(:query).with("#{@model_query} AND foo:bar", :rows=>0, :raw=>true).returns(mock_result)
174
187
  SpecModel::Basic.count(:conditions=>'foo:bar').should == 7
175
188
  end
189
+
190
+ it "should count without a class specified" do
191
+ mock_result = {'response'=>{'numFound'=>7}}
192
+ ActiveFedora::SolrService.expects(:query).with("foo:bar", :rows=>0, :raw=>true).returns(mock_result)
193
+ ActiveFedora::Base.count(:conditions=>'foo:bar').should == 7
194
+ end
176
195
  end
177
196
 
178
197
  describe '#find_by_solr' do
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveFedora::Attributes::Serializers do
4
+ subject { ActiveFedora::Base }
5
+ describe "serialize to integer" do
6
+ it "should cast to integer" do
7
+ subject.coerce_to_integer("0").should == 0
8
+ subject.coerce_to_integer("01").should == 1
9
+ subject.coerce_to_integer("seven").should == 0 # same as "seven".to_i => 0
10
+ subject.coerce_to_integer("007seven").should == 7 # same as "007seven".to_i => 7
11
+ subject.coerce_to_integer("").should be_nil
12
+ subject.coerce_to_integer(nil).should be_nil
13
+ subject.coerce_to_integer("", :default=>7).should == 7
14
+ subject.coerce_to_integer(nil, :default=>7).should == 7
15
+ subject.coerce_to_integer("9", :default=>7).should == 9
16
+ end
17
+ end
18
+
19
+ describe "serialize to date" do
20
+ it "should cast to date" do
21
+ unless RUBY_VERSION < "1.9"
22
+ subject.coerce_to_date("30/10/2010").should == Date.parse('2010-10-30') # ruby interprets this as DD/MM/YYYY
23
+ end
24
+ subject.coerce_to_date("2010-01-31").should == Date.parse('2010-01-31')
25
+ end
26
+ it "should handle invalid dates" do
27
+ subject.coerce_to_date("0").should == nil #
28
+ unless RUBY_VERSION < "1.9"
29
+ subject.coerce_to_date("01/15/2010").should == nil # ruby interprets this as DD/MM/YYYY
30
+ end
31
+ subject.coerce_to_date("2010-31-01").should == nil
32
+ end
33
+ it "should work with a blank string" do
34
+ subject.coerce_to_date("").should == nil
35
+ subject.coerce_to_date("", :default=>:today).should be_kind_of Date
36
+ subject.coerce_to_date("", :default=>Date.parse('2010-01-31')).should == Date.parse('2010-01-31')
37
+ end
38
+ it "should work when nil is passed in" do
39
+ subject.coerce_to_date(nil).should == nil
40
+ subject.coerce_to_date(nil, :default=>:today).should be_kind_of Date
41
+ subject.coerce_to_date(nil, :default=>Date.parse('2010-01-31')).should == Date.parse('2010-01-31')
42
+ end
43
+ end
44
+ describe "serialize to boolean" do
45
+ it "should cast to bool" do
46
+ subject.coerce_to_boolean("true").should be_true
47
+ subject.coerce_to_boolean("false").should be_false
48
+ subject.coerce_to_boolean("faoo").should be_false
49
+ subject.coerce_to_boolean("").should be_false
50
+ subject.coerce_to_boolean("", :default=>true).should be_true
51
+ subject.coerce_to_boolean("", :default=>false).should be_false
52
+ subject.coerce_to_boolean("x", :default=>true).should be_false
53
+ subject.coerce_to_boolean("x", :default=>false).should be_false
54
+ subject.coerce_to_boolean(nil, :default=>true).should be_true
55
+ subject.coerce_to_boolean(nil, :default=>false).should be_false
56
+ end
57
+ end
58
+
59
+ describe "deserialize_dates_from_form" do
60
+ before do
61
+ class Foo < ActiveFedora::Base
62
+ attr_accessor :birthday
63
+ end
64
+ end
65
+ after do
66
+ Object.send(:remove_const, :Foo)
67
+ end
68
+ subject { Foo.new }
69
+ it "should deserialize dates" do
70
+ subject.attributes = {'birthday(1i)' =>'2012', 'birthday(2i)' =>'10', 'birthday(3i)' => '31'}
71
+ subject.birthday.should == '2012-10-31'
72
+ end
73
+ end
74
+
75
+ end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active-fedora
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.3
5
- prerelease:
4
+ version: 4.6.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Matt Zumwalt
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-10-08 00:00:00.000000000 Z
14
+ date: 2012-10-12 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rsolr
@@ -93,6 +93,22 @@ dependencies:
93
93
  - - ! '>='
94
94
  - !ruby/object:Gem::Version
95
95
  version: 3.0.0
96
+ - !ruby/object:Gem::Dependency
97
+ name: builder
98
+ requirement: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ version: 3.0.0
96
112
  - !ruby/object:Gem::Dependency
97
113
  name: mediashelf-loggable
98
114
  requirement: !ruby/object:Gem::Requirement
@@ -328,6 +344,8 @@ files:
328
344
  - lib/active_fedora/associations/belongs_to_association.rb
329
345
  - lib/active_fedora/associations/has_and_belongs_to_many_association.rb
330
346
  - lib/active_fedora/associations/has_many_association.rb
347
+ - lib/active_fedora/attributes.rb
348
+ - lib/active_fedora/attributes/serializers.rb
331
349
  - lib/active_fedora/base.rb
332
350
  - lib/active_fedora/callbacks.rb
333
351
  - lib/active_fedora/config.rb
@@ -417,6 +435,7 @@ files:
417
435
  - spec/integration/nested_attribute_spec.rb
418
436
  - spec/integration/nokogiri_datastream_spec.rb
419
437
  - spec/integration/ntriples_datastream_spec.rb
438
+ - spec/integration/persistence_spec.rb
420
439
  - spec/integration/rels_ext_datastream_spec.rb
421
440
  - spec/integration/semantic_node_spec.rb
422
441
  - spec/integration/solr_service_spec.rb
@@ -501,6 +520,7 @@ files:
501
520
  - spec/unit/rels_ext_datastream_spec.rb
502
521
  - spec/unit/rubydora_connection_spec.rb
503
522
  - spec/unit/semantic_node_spec.rb
523
+ - spec/unit/serializers_spec.rb
504
524
  - spec/unit/service_definitions_spec.rb
505
525
  - spec/unit/simple_datastream_spec.rb
506
526
  - spec/unit/solr_config_options_spec.rb
@@ -520,12 +540,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
520
540
  - - ! '>='
521
541
  - !ruby/object:Gem::Version
522
542
  version: '0'
543
+ segments:
544
+ - 0
545
+ hash: 190185801018639774
523
546
  required_rubygems_version: !ruby/object:Gem::Requirement
524
547
  none: false
525
548
  requirements:
526
- - - ! '>='
549
+ - - ! '>'
527
550
  - !ruby/object:Gem::Version
528
- version: '0'
551
+ version: 1.3.1
529
552
  requirements: []
530
553
  rubyforge_project: rubyfedora
531
554
  rubygems_version: 1.8.24
@@ -569,6 +592,7 @@ test_files:
569
592
  - spec/integration/nested_attribute_spec.rb
570
593
  - spec/integration/nokogiri_datastream_spec.rb
571
594
  - spec/integration/ntriples_datastream_spec.rb
595
+ - spec/integration/persistence_spec.rb
572
596
  - spec/integration/rels_ext_datastream_spec.rb
573
597
  - spec/integration/semantic_node_spec.rb
574
598
  - spec/integration/solr_service_spec.rb
@@ -653,6 +677,7 @@ test_files:
653
677
  - spec/unit/rels_ext_datastream_spec.rb
654
678
  - spec/unit/rubydora_connection_spec.rb
655
679
  - spec/unit/semantic_node_spec.rb
680
+ - spec/unit/serializers_spec.rb
656
681
  - spec/unit/service_definitions_spec.rb
657
682
  - spec/unit/simple_datastream_spec.rb
658
683
  - spec/unit/solr_config_options_spec.rb