active-fedora 8.7.0 → 9.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (242) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +8 -15
  3. data/Gemfile +5 -5
  4. data/History.txt +0 -80
  5. data/README.md +1 -0
  6. data/Rakefile +0 -3
  7. data/active-fedora.gemspec +8 -7
  8. data/config/fedora.yml +5 -4
  9. data/config/predicate_mappings.yml +5 -5
  10. data/gemfiles/rails4.1.gemfile +10 -0
  11. data/gemfiles/rails4.2.beta.gemfile +10 -0
  12. data/lib/active_fedora.rb +151 -117
  13. data/lib/active_fedora/associations.rb +47 -15
  14. data/lib/active_fedora/associations/association.rb +29 -8
  15. data/lib/active_fedora/associations/association_scope.rb +5 -5
  16. data/lib/active_fedora/associations/belongs_to_association.rb +20 -63
  17. data/lib/active_fedora/associations/builder/association.rb +61 -25
  18. data/lib/active_fedora/associations/builder/belongs_to.rb +7 -94
  19. data/lib/active_fedora/associations/builder/collection_association.rb +11 -43
  20. data/lib/active_fedora/associations/builder/contains.rb +28 -0
  21. data/lib/active_fedora/associations/builder/has_and_belongs_to_many.rb +13 -3
  22. data/lib/active_fedora/associations/builder/has_many.rb +16 -10
  23. data/lib/active_fedora/associations/builder/property.rb +14 -0
  24. data/lib/active_fedora/associations/builder/singular_association.rb +14 -18
  25. data/lib/active_fedora/associations/builder/singular_property.rb +12 -0
  26. data/lib/active_fedora/associations/collection_association.rb +57 -80
  27. data/lib/active_fedora/associations/contains_association.rb +50 -0
  28. data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +44 -24
  29. data/lib/active_fedora/associations/has_many_association.rb +46 -14
  30. data/lib/active_fedora/associations/rdf.rb +86 -0
  31. data/lib/active_fedora/associations/singular_association.rb +4 -8
  32. data/lib/active_fedora/associations/singular_rdf.rb +15 -0
  33. data/lib/active_fedora/attached_files.rb +195 -0
  34. data/lib/active_fedora/attribute_methods.rb +122 -0
  35. data/lib/active_fedora/attribute_methods/dirty.rb +16 -0
  36. data/lib/active_fedora/attribute_methods/read.rb +61 -0
  37. data/lib/active_fedora/attribute_methods/write.rb +47 -0
  38. data/lib/active_fedora/attributes.rb +93 -44
  39. data/lib/active_fedora/attributes/primary_key.rb +12 -0
  40. data/lib/active_fedora/autosave_association.rb +2 -2
  41. data/lib/active_fedora/base.rb +16 -15
  42. data/lib/active_fedora/callbacks.rb +7 -7
  43. data/lib/active_fedora/change_set.rb +34 -0
  44. data/lib/active_fedora/cleaner.rb +62 -0
  45. data/lib/active_fedora/config.rb +4 -22
  46. data/lib/active_fedora/core.rb +173 -99
  47. data/lib/active_fedora/datastream.rb +4 -117
  48. data/lib/active_fedora/datastreams.rb +2 -263
  49. data/lib/active_fedora/datastreams/nokogiri_datastreams.rb +28 -51
  50. data/lib/active_fedora/{datastream_attribute.rb → delegated_attribute.rb} +57 -26
  51. data/lib/active_fedora/errors.rb +61 -0
  52. data/lib/active_fedora/fedora.rb +19 -0
  53. data/lib/active_fedora/fedora_attributes.rb +58 -26
  54. data/lib/active_fedora/file.rb +318 -0
  55. data/lib/active_fedora/file_configurator.rb +32 -32
  56. data/lib/active_fedora/file_path_builder.rb +24 -0
  57. data/lib/active_fedora/files_hash.rb +82 -0
  58. data/lib/active_fedora/fixity_service.rb +40 -0
  59. data/lib/active_fedora/indexing.rb +55 -82
  60. data/lib/active_fedora/indexing_service.rb +70 -0
  61. data/lib/active_fedora/ldp_resource.rb +26 -0
  62. data/lib/active_fedora/loadable_from_json.rb +112 -0
  63. data/lib/active_fedora/model.rb +5 -19
  64. data/lib/active_fedora/nested_attributes.rb +5 -6
  65. data/lib/active_fedora/nom_datastream.rb +15 -25
  66. data/lib/active_fedora/om_datastream.rb +26 -197
  67. data/lib/active_fedora/persistence.rb +95 -71
  68. data/lib/active_fedora/predicates.rb +4 -4
  69. data/lib/active_fedora/qualified_dublin_core_datastream.rb +17 -18
  70. data/lib/active_fedora/querying.rb +3 -4
  71. data/lib/active_fedora/railtie.rb +3 -6
  72. data/lib/active_fedora/rdf.rb +3 -1
  73. data/lib/active_fedora/rdf/datastream_indexing.rb +11 -0
  74. data/lib/active_fedora/rdf/fcrepo.rb +10 -324
  75. data/lib/active_fedora/rdf/indexing.rb +20 -16
  76. data/lib/active_fedora/rdf/ldp.rb +6 -0
  77. data/lib/active_fedora/rdf/ntriples_rdf_datastream.rb +1 -1
  78. data/lib/active_fedora/rdf/persistence.rb +5 -6
  79. data/lib/active_fedora/rdf/rdf_datastream.rb +44 -37
  80. data/lib/active_fedora/rdf/rdfxml_datastream.rb +13 -0
  81. data/lib/active_fedora/rdf/rels_ext.rb +26 -0
  82. data/lib/active_fedora/reflection.rb +256 -199
  83. data/lib/active_fedora/relation.rb +18 -6
  84. data/lib/active_fedora/relation/finder_methods.rb +69 -38
  85. data/lib/active_fedora/relation/query_methods.rb +7 -3
  86. data/lib/active_fedora/rspec_matchers/belong_to_associated_active_fedora_object_matcher.rb +7 -7
  87. data/lib/active_fedora/rspec_matchers/have_many_associated_active_fedora_objects_matcher.rb +8 -8
  88. data/lib/active_fedora/rspec_matchers/have_predicate_matcher.rb +9 -11
  89. data/lib/active_fedora/simple_datastream.rb +18 -13
  90. data/lib/active_fedora/solr_instance_loader.rb +18 -38
  91. data/lib/active_fedora/solr_service.rb +37 -20
  92. data/lib/active_fedora/sparql_insert.rb +45 -0
  93. data/lib/active_fedora/test_support.rb +1 -22
  94. data/lib/active_fedora/version.rb +1 -1
  95. data/lib/active_fedora/versionable.rb +90 -0
  96. data/lib/active_fedora/with_metadata.rb +37 -0
  97. data/lib/active_fedora/with_metadata/metadata_node.rb +70 -0
  98. data/lib/generators/active_fedora/config/config_generator.rb +0 -1
  99. data/lib/generators/active_fedora/config/solr/solr_generator.rb +1 -1
  100. data/lib/generators/active_fedora/model/model_generator.rb +5 -5
  101. data/lib/generators/active_fedora/model/templates/datastream_spec.rb.erb +1 -1
  102. data/lib/generators/active_fedora/model/templates/model_spec.rb.erb +2 -2
  103. data/lib/tasks/active_fedora_dev.rake +21 -27
  104. data/spec/config_helper.rb +1 -1
  105. data/spec/fixtures/mixed_rdf_descMetadata.nt +6 -6
  106. data/spec/fixtures/rails_root/config/predicate_mappings.yml +3 -19
  107. data/spec/fixtures/solr_rdf_descMetadata.nt +6 -6
  108. data/spec/integration/associations_spec.rb +133 -153
  109. data/spec/integration/attached_files_spec.rb +164 -0
  110. data/spec/integration/attributes_spec.rb +73 -12
  111. data/spec/integration/autosave_association_spec.rb +3 -3
  112. data/spec/integration/base_spec.rb +57 -351
  113. data/spec/integration/belongs_to_association_spec.rb +86 -76
  114. data/spec/integration/bug_spec.rb +3 -3
  115. data/spec/integration/collection_association_spec.rb +4 -4
  116. data/spec/integration/complex_rdf_datastream_spec.rb +54 -56
  117. data/spec/integration/delete_all_spec.rb +18 -15
  118. data/spec/integration/eradicate_spec.rb +54 -0
  119. data/spec/integration/fedora_solr_sync_spec.rb +7 -5
  120. data/spec/integration/field_to_solr_name_spec.rb +5 -5
  121. data/spec/integration/file_fixity_spec.rb +40 -0
  122. data/spec/integration/file_spec.rb +122 -0
  123. data/spec/integration/full_featured_model_spec.rb +53 -63
  124. data/spec/integration/has_and_belongs_to_many_associations_spec.rb +141 -114
  125. data/spec/integration/has_many_associations_spec.rb +142 -64
  126. data/spec/integration/json_serialization_spec.rb +50 -8
  127. data/spec/integration/model_spec.rb +12 -29
  128. data/spec/integration/nested_attribute_spec.rb +28 -20
  129. data/spec/integration/ntriples_datastream_spec.rb +60 -57
  130. data/spec/integration/om_datastream_spec.rb +51 -140
  131. data/spec/integration/rdf_nested_attributes_spec.rb +16 -14
  132. data/spec/integration/relation_delegation_spec.rb +7 -9
  133. data/spec/integration/relation_spec.rb +9 -7
  134. data/spec/integration/scoped_query_spec.rb +26 -26
  135. data/spec/integration/solr_instance_loader_spec.rb +69 -53
  136. data/spec/integration/solr_service_spec.rb +12 -73
  137. data/spec/integration/versionable_spec.rb +477 -0
  138. data/spec/integration/with_metadata_spec.rb +52 -0
  139. data/spec/samples/hydra-mods_article_datastream.rb +10 -6
  140. data/spec/samples/models/mods_article.rb +6 -2
  141. data/spec/samples/oral_history_sample.xml +1 -1
  142. data/spec/samples/oral_history_xml.xml +1 -1
  143. data/spec/samples/special_thing.rb +3 -3
  144. data/spec/spec_helper.rb +22 -12
  145. data/spec/support/an_active_model.rb +3 -7
  146. data/spec/unit/active_fedora_spec.rb +20 -17
  147. data/spec/unit/attached_files_spec.rb +203 -0
  148. data/spec/unit/attributes_spec.rb +286 -207
  149. data/spec/unit/base_active_model_spec.rb +8 -8
  150. data/spec/unit/base_datastream_management_spec.rb +11 -24
  151. data/spec/unit/base_extra_spec.rb +17 -67
  152. data/spec/unit/base_spec.rb +163 -428
  153. data/spec/unit/builder/has_and_belongs_to_many_spec.rb +2 -2
  154. data/spec/unit/callback_spec.rb +38 -23
  155. data/spec/unit/change_set_spec.rb +46 -0
  156. data/spec/unit/code_configurator_spec.rb +5 -5
  157. data/spec/unit/config_spec.rb +9 -14
  158. data/spec/unit/core_spec.rb +59 -8
  159. data/spec/unit/file_configurator_spec.rb +55 -53
  160. data/spec/unit/file_path_builder_spec.rb +18 -0
  161. data/spec/unit/file_spec.rb +221 -0
  162. data/spec/unit/files_hash_spec.rb +53 -0
  163. data/spec/unit/fixity_service_spec.rb +34 -0
  164. data/spec/unit/has_and_belongs_to_many_association_spec.rb +134 -0
  165. data/spec/unit/has_many_association_spec.rb +51 -0
  166. data/spec/unit/indexing_service_spec.rb +23 -0
  167. data/spec/unit/indexing_spec.rb +26 -0
  168. data/spec/unit/inheritance_spec.rb +9 -10
  169. data/spec/unit/model_spec.rb +15 -33
  170. data/spec/unit/nom_datastream_spec.rb +13 -10
  171. data/spec/unit/ntriples_datastream_spec.rb +81 -96
  172. data/spec/unit/om_datastream_spec.rb +137 -227
  173. data/spec/unit/persistence_spec.rb +28 -34
  174. data/spec/unit/predicates_spec.rb +29 -29
  175. data/spec/unit/property_spec.rb +1 -3
  176. data/spec/unit/qualified_dublin_core_datastream_spec.rb +27 -32
  177. data/spec/unit/query_spec.rb +116 -149
  178. data/spec/unit/rdf_datastream_spec.rb +25 -43
  179. data/spec/unit/rdf_resource_datastream_spec.rb +24 -123
  180. data/spec/unit/{rdfxml_rdf_datastream_spec.rb → rdfxml_datastream_spec.rb} +21 -25
  181. data/spec/unit/readonly_spec.rb +23 -0
  182. data/spec/unit/rspec_matchers/belong_to_associated_active_fedora_object_matcher_spec.rb +6 -6
  183. data/spec/unit/rspec_matchers/have_many_associated_active_fedora_objects_matcher_spec.rb +6 -6
  184. data/spec/unit/rspec_matchers/have_predicate_matcher_spec.rb +6 -6
  185. data/spec/unit/serializers_spec.rb +1 -1
  186. data/spec/unit/simple_datastream_spec.rb +12 -23
  187. data/spec/unit/solr_config_options_spec.rb +14 -17
  188. data/spec/unit/solr_service_spec.rb +38 -77
  189. data/spec/unit/sparql_insert_spec.rb +32 -0
  190. data/spec/unit/validations_spec.rb +8 -11
  191. metadata +96 -121
  192. data/lib/active_fedora/auditable.rb +0 -9
  193. data/lib/active_fedora/content_model.rb +0 -70
  194. data/lib/active_fedora/datastream_collections.rb +0 -302
  195. data/lib/active_fedora/datastream_hash.rb +0 -35
  196. data/lib/active_fedora/digital_object.rb +0 -55
  197. data/lib/active_fedora/fixture_exporter.rb +0 -33
  198. data/lib/active_fedora/fixture_loader.rb +0 -48
  199. data/lib/active_fedora/rdf/identifiable.rb +0 -66
  200. data/lib/active_fedora/rdf/project_hydra.rb +0 -12
  201. data/lib/active_fedora/rdf/rdfxml_rdf_datastream.rb +0 -13
  202. data/lib/active_fedora/rdf_xml_writer.rb +0 -49
  203. data/lib/active_fedora/relationship_graph.rb +0 -101
  204. data/lib/active_fedora/reload_on_save.rb +0 -16
  205. data/lib/active_fedora/rels_ext_datastream.rb +0 -100
  206. data/lib/active_fedora/rspec_matchers/match_fedora_datastream_matcher.rb +0 -41
  207. data/lib/active_fedora/rubydora_connection.rb +0 -35
  208. data/lib/active_fedora/semantic_node.rb +0 -164
  209. data/lib/active_fedora/service_definitions.rb +0 -88
  210. data/lib/active_fedora/sharding.rb +0 -58
  211. data/lib/active_fedora/solr_digital_object.rb +0 -68
  212. data/lib/active_fedora/unsaved_digital_object.rb +0 -58
  213. data/lib/generators/active_fedora/config/fedora/fedora_generator.rb +0 -12
  214. data/lib/generators/active_fedora/config/fedora/templates/fedora.yml +0 -38
  215. data/lib/generators/active_fedora/config/fedora/templates/fedora_conf/conf/development/fedora.fcfg +0 -953
  216. data/lib/generators/active_fedora/config/fedora/templates/fedora_conf/conf/test/fedora.fcfg +0 -953
  217. data/lib/tasks/active_fedora.rake +0 -83
  218. data/spec/fixtures/sharded_fedora.yml +0 -11
  219. data/spec/integration/auditable_spec.rb +0 -29
  220. data/spec/integration/datastream_collections_spec.rb +0 -127
  221. data/spec/integration/datastream_spec.rb +0 -90
  222. data/spec/integration/datastreams_spec.rb +0 -173
  223. data/spec/integration/load_from_solr_spec.rb +0 -66
  224. data/spec/integration/rels_ext_datastream_spec.rb +0 -82
  225. data/spec/support/mock_fedora.rb +0 -44
  226. data/spec/unit/content_model_spec.rb +0 -86
  227. data/spec/unit/datastream_collections_spec.rb +0 -420
  228. data/spec/unit/datastream_spec.rb +0 -83
  229. data/spec/unit/datastreams_spec.rb +0 -243
  230. data/spec/unit/has_and_belongs_to_many_collection_spec.rb +0 -96
  231. data/spec/unit/has_many_collection_spec.rb +0 -35
  232. data/spec/unit/rdf_vocab_spec.rb +0 -30
  233. data/spec/unit/rdf_xml_writer_spec.rb +0 -63
  234. data/spec/unit/relationship_graph_spec.rb +0 -115
  235. data/spec/unit/reload_on_save_spec.rb +0 -24
  236. data/spec/unit/rels_ext_datastream_spec.rb +0 -170
  237. data/spec/unit/rspec_matchers/match_fedora_datastream_matcher_spec.rb +0 -44
  238. data/spec/unit/rubydora_connection_spec.rb +0 -12
  239. data/spec/unit/semantic_node_spec.rb +0 -112
  240. data/spec/unit/service_definitions_spec.rb +0 -63
  241. data/spec/unit/solr_digital_object_spec.rb +0 -97
  242. data/spec/unit/unsaved_digital_object_spec.rb +0 -48
@@ -2,100 +2,13 @@ module ActiveFedora::Associations::Builder
2
2
  class BelongsTo < SingularAssociation #:nodoc:
3
3
  self.macro = :belongs_to
4
4
 
5
- self.valid_options += [:touch]
6
-
7
-
8
- def build
9
- reflection = super
10
- add_counter_cache_callbacks(reflection) if options[:counter_cache]
11
- add_touch_callbacks(reflection) if options[:touch]
12
- configure_dependency
13
- reflection
14
- end
15
-
16
- private
17
-
18
- def add_counter_cache_callbacks(reflection)
19
- cache_column = reflection.counter_cache_column
20
- name = self.name
21
-
22
- method_name = "belongs_to_counter_cache_after_create_for_#{name}"
23
- mixin.redefine_method(method_name) do
24
- record = send(name)
25
- record.class.increment_counter(cache_column, record.id) unless record.nil?
26
- end
27
- model.after_create(method_name)
28
-
29
- method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
30
- mixin.redefine_method(method_name) do
31
- record = send(name)
32
- record.class.decrement_counter(cache_column, record.id) unless record.nil?
33
- end
34
- model.before_destroy(method_name)
35
-
36
- model.send(:module_eval,
37
- "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)", __FILE__, __LINE__
38
- )
39
- end
40
-
41
- def add_touch_callbacks(reflection)
42
- name = self.name
43
- method_name = "belongs_to_touch_after_save_or_destroy_for_#{name}"
44
- touch = options[:touch]
45
-
46
- mixin.redefine_method(method_name) do
47
- record = send(name)
48
-
49
- unless record.nil?
50
- if touch == true
51
- record.touch
52
- else
53
- record.touch(touch)
54
- end
55
- end
56
- end
57
-
58
- model.after_save(method_name)
59
- model.after_touch(method_name)
60
- model.after_destroy(method_name)
61
- end
62
-
63
- def configure_dependency
64
- if options[:dependent]
65
- unless [:destroy, :delete].include?(options[:dependent])
66
- raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{options[:dependent].inspect})"
67
- end
68
-
69
- method_name = "belongs_to_dependent_#{options[:dependent]}_for_#{name}"
70
- model.send(:class_eval, <<-eoruby, __FILE__, __LINE__ + 1)
71
- def #{method_name}
72
- association = #{name}
73
- association.#{options[:dependent]} if association
74
- end
75
- eoruby
76
- model.after_destroy method_name
77
- end
78
- end
79
-
80
- def define_readers
81
- super
82
- name = self.name
83
- accessor_name = "#{name}_id"
84
- model.find_or_create_defined_attribute(accessor_name, 'RELS-EXT', {})
85
- mixin.redefine_method(accessor_name) do
86
- association(name).id_reader
87
- end
88
- end
89
-
90
- def define_writers
91
- super
92
- name = self.name
93
- writer_name = "#{name}_id"
94
- model.find_or_create_defined_attribute(writer_name, 'RELS-EXT', {})
95
- mixin.redefine_method("#{writer_name}=") do |id|
96
- raise "can't modify frozen #{self.class}" if self.frozen?
97
- association(name).id_writer(id)
98
- end
5
+ def validate_options
6
+ super
7
+ if !options[:predicate]
8
+ raise "You must specify a predicate for #{name}"
9
+ elsif !options[:predicate].kind_of?(RDF::URI)
10
+ raise ArgumentError, "Predicate must be a kind of RDF::URI"
99
11
  end
12
+ end
100
13
  end
101
14
  end
@@ -1,56 +1,24 @@
1
+ require 'active_fedora/associations'
1
2
  module ActiveFedora::Associations::Builder
2
3
  class CollectionAssociation < Association #:nodoc:
3
4
  CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
4
5
 
5
- self.valid_options += [
6
+ self.valid_options += [
6
7
  :before_add, :after_add, :before_remove, :after_remove
7
8
  ]
8
9
 
9
-
10
- def self.build(model, name, options)
11
- new(model, name, options).build
12
- end
13
-
14
- def initialize(model, name, options)
15
- super(model, name, options)
10
+ def self.define_callbacks(model, reflection)
11
+ name = reflection.name
12
+ options = reflection.options
13
+ CALLBACKS.each { |callback_name| define_callback(model, callback_name, name, options) }
16
14
  end
17
15
 
18
- def build
19
- reflection = super
20
- CALLBACKS.each { |callback_name| define_callback(callback_name) }
21
- reflection
22
- end
16
+ def self.define_callback(model, callback_name, name, options)
17
+ full_callback_name = "#{callback_name}_for_#{name}"
23
18
 
24
- def writable?
25
- true
19
+ # TODO : why do i need method_defined? I think its because of the inheritance chain
20
+ model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
21
+ model.send("#{full_callback_name}=", Array(options[callback_name.to_sym]))
26
22
  end
27
-
28
- private
29
-
30
- def define_callback(callback_name)
31
- full_callback_name = "#{callback_name}_for_#{name}"
32
-
33
- # TODO : why do i need method_defined? I think its because of the inheritance chain
34
- model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
35
- model.send("#{full_callback_name}=", Array(options[callback_name.to_sym]))
36
- end
37
-
38
- def define_readers
39
- super
40
-
41
- name = self.name
42
- mixin.redefine_method("#{name.to_s.singularize}_ids") do
43
- association(name).ids_reader
44
- end
45
- end
46
-
47
- def define_writers
48
- super
49
-
50
- name = self.name
51
- mixin.redefine_method("#{name.to_s.singularize}_ids=") do |ids|
52
- association(name).ids_writer(ids)
53
- end
54
- end
55
23
  end
56
24
  end
@@ -0,0 +1,28 @@
1
+ module ActiveFedora::Associations::Builder
2
+ class Contains < SingularAssociation #:nodoc:
3
+ self.macro = :contains
4
+ self.valid_options += [:autocreate, :block]
5
+
6
+ def initialize(model, name, options)
7
+ super
8
+ options[:class_name] = 'ActiveFedora::File' if options[:class_name].blank?
9
+ end
10
+
11
+ def validate_options
12
+ super
13
+ if options[:class_name] && !options[:class_name].is_a?(String)
14
+ raise ArgumentError, ":class_name must be a string for contains '#{name}'" unless options[:class_name].is_a? String
15
+ end
16
+ end
17
+
18
+ def self.define_readers(mixin, name)
19
+ mixin.send(:define_method, name) do |*params|
20
+ association(name).reader(*params).tap do |file|
21
+ set_uri = uri.kind_of?(RDF::URI) ? uri.value.present? : uri.present?
22
+ file.uri = "#{uri}/#{name}" if set_uri
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -4,23 +4,33 @@ module ActiveFedora::Associations::Builder
4
4
 
5
5
  self.valid_options += [:inverse_of, :solr_page_size]
6
6
 
7
+ def validate_options
8
+ super
9
+ if !options[:predicate]
10
+ raise "You must specify a predicate for #{name}"
11
+ elsif !options[:predicate].kind_of?(RDF::URI)
12
+ raise ArgumentError, "Predicate must be a kind of RDF::URI"
13
+ end
14
+ end
15
+
7
16
  def build
8
17
  reflection = super
9
- redefine_destroy
18
+ define_destroy_hook
10
19
  reflection
11
20
  end
12
21
 
13
22
  private
14
23
 
15
- def redefine_destroy
24
+ def define_destroy_hook
16
25
  # Don't use a before_destroy callback since users' before_destroy
17
26
  # callbacks will be executed after the association is wiped out.
27
+ # TODO Update to destroy_associations
18
28
  name = self.name
19
29
  model.send(:include, Module.new {
20
30
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
21
31
  def destroy # def destroy
22
- super # super
23
32
  #{name}.clear # posts.clear
33
+ super # super
24
34
  end # end
25
35
  RUBY
26
36
  })
@@ -10,6 +10,22 @@ module ActiveFedora::Associations::Builder
10
10
  reflection
11
11
  end
12
12
 
13
+ def self.define_readers(mixin, name)
14
+ super
15
+
16
+ mixin.redefine_method("#{name.to_s.singularize}_ids") do
17
+ association(name).ids_reader
18
+ end
19
+ end
20
+
21
+ def self.define_writers(mixin, name)
22
+ super
23
+
24
+ mixin.redefine_method("#{name.to_s.singularize}_ids=") do |ids|
25
+ association(name).ids_writer(ids)
26
+ end
27
+ end
28
+
13
29
  private
14
30
 
15
31
  def configure_dependency
@@ -27,16 +43,6 @@ module ActiveFedora::Associations::Builder
27
43
  def define_destroy_dependency_method
28
44
  name = self.name
29
45
  model.send(:define_method, dependency_method_name) do
30
- send(name).each do |o|
31
- # No point in executing the counter update since we're going to destroy the parent anyway
32
- counter_method = ('belongs_to_counter_cache_before_destroy_for_' + self.class.name.downcase).to_sym
33
- if o.respond_to?(counter_method)
34
- class << o
35
- self
36
- end.send(:define_method, counter_method, Proc.new {})
37
- end
38
- end
39
-
40
46
  send(name).delete_all
41
47
  end
42
48
  end
@@ -0,0 +1,14 @@
1
+ module ActiveFedora::Associations::Builder
2
+ class Property < Association
3
+
4
+ self.macro = :rdf
5
+ self.valid_options = [:class_name, :predicate]
6
+
7
+ def initialize(model, name, options)
8
+ super
9
+ @name = :"#{name.to_s.singularize}_ids"
10
+ end
11
+
12
+ end
13
+ end
14
+
@@ -1,32 +1,28 @@
1
1
  module ActiveFedora::Associations::Builder
2
2
  class SingularAssociation < Association #:nodoc:
3
- self.valid_options += [:dependent, :counter_cache, :inverse_of]
3
+ self.valid_options += [:dependent, :inverse_of]
4
4
 
5
- def constructable?
5
+ def self.constructable?
6
6
  true
7
7
  end
8
8
 
9
- def define_accessors
9
+ def self.define_accessors(model, reflection)
10
10
  super
11
- define_constructors if constructable?
11
+ define_constructors(model.generated_association_methods, reflection.name) if constructable?
12
12
  end
13
13
 
14
- private
15
-
16
- def define_constructors
17
- name = self.name
18
-
19
- mixin.redefine_method("build_#{name}") do |*params|
20
- association(name).build(*params)
21
- end
14
+ def self.define_constructors(mixin, name)
15
+ mixin.redefine_method("build_#{name}") do |*params|
16
+ association(name).build(*params)
17
+ end
22
18
 
23
- mixin.redefine_method("create_#{name}") do |*params|
24
- association(name).create(*params)
25
- end
19
+ mixin.redefine_method("create_#{name}") do |*params|
20
+ association(name).create(*params)
21
+ end
26
22
 
27
- mixin.redefine_method("create_#{name}!") do |*params|
28
- association(name).create!(*params)
29
- end
23
+ mixin.redefine_method("create_#{name}!") do |*params|
24
+ association(name).create!(*params)
30
25
  end
26
+ end
31
27
  end
32
28
  end
@@ -0,0 +1,12 @@
1
+ module ActiveFedora::Associations::Builder
2
+ class SingularProperty < Property
3
+
4
+ self.macro = :singular_rdf
5
+
6
+ def initialize(model, name, options)
7
+ super
8
+ @name = :"#{name}_id"
9
+ end
10
+
11
+ end
12
+ end
@@ -5,9 +5,7 @@ module ActiveFedora
5
5
 
6
6
  def initialize(owner, reflection)
7
7
  super
8
-
9
8
  construct_query
10
- @proxy = CollectionProxy.new(self)
11
9
  end
12
10
 
13
11
 
@@ -17,14 +15,14 @@ module ActiveFedora
17
15
  def reader(opts = false)
18
16
  if opts.kind_of?(Hash)
19
17
  if opts.delete(:response_format) == :solr
20
- return load_from_solr(opts)
18
+ return load_from_solr(opts)
21
19
  end
22
20
  raise ArgumentError, "Hash parameter must include :response_format=>:solr (#{opts.inspect})"
23
21
  else
24
22
  force_reload = opts
25
23
  end
26
24
  reload if force_reload || stale_target?
27
- proxy
25
+ @proxy ||= CollectionProxy.new(self)
28
26
  end
29
27
 
30
28
  # Implements the writer method, e.g. foo.items= for Foo.has_many :items
@@ -36,7 +34,7 @@ module ActiveFedora
36
34
  def ids_reader
37
35
  if loaded?
38
36
  load_target.map do |record|
39
- record.pid
37
+ record.id
40
38
  end
41
39
  else
42
40
  load_from_solr.map do |solr_record|
@@ -71,7 +69,7 @@ module ActiveFedora
71
69
  first_or_last(:last, *args)
72
70
  end
73
71
 
74
- # Returns the size of the collection
72
+ # Returns the size of the collection
75
73
  #
76
74
  # If the collection has been already loaded +size+ and +length+ are
77
75
  # equivalent. If not and you are going to need the records anyway
@@ -117,7 +115,7 @@ module ActiveFedora
117
115
  delete(@target.select { |v| !other.include?(v) })
118
116
  concat(other_array.select { |v| !current.include?(v) })
119
117
  end
120
-
118
+
121
119
  def include?(record)
122
120
  if record.is_a?(reflection.klass)
123
121
  if record.new_record?
@@ -147,37 +145,37 @@ module ActiveFedora
147
145
  if attributes.is_a?(Array)
148
146
  attributes.collect { |attr| build(attr, &block) }
149
147
  else
150
- build_record(attributes) do |record|
151
- block.call(record) if block_given?
152
- add_to_target(record)
153
- set_belongs_to_association_for(record)
148
+ add_to_target(build_record(attributes)) do |record|
149
+ yield(record) if block_given?
154
150
  end
155
151
  end
156
152
  end
157
153
 
158
154
  # Add +records+ to this association. Returns +self+ so method calls may be chained.
159
155
  # Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically.
160
- def <<(*records)
156
+ def concat(*records)
157
+ load_target unless owner.new_record?
158
+ concat_records(records)
159
+ end
160
+
161
+ def concat_records(*records)
161
162
  result = true
162
- load_target unless loaded?
163
163
 
164
164
  records.flatten.each do |record|
165
165
  raise_on_type_mismatch(record)
166
- add_record_to_target_with_callbacks(record) do |r|
167
- result &&= insert_record(record)
166
+ add_to_target(record) do |r|
167
+ result &&= insert_record(record) unless owner.new_record?
168
168
  end
169
169
  end
170
170
 
171
- result && self
171
+ result && records
172
172
  end
173
173
 
174
- alias_method :push, :<<
175
- alias_method :concat, :<<
176
-
177
174
  # Remove all records from this association
178
175
  #
179
176
  # See delete for more info.
180
177
  def delete_all
178
+ # TODO load_target causes extra loads. Can't we just send delete requests?
181
179
  delete(load_target).tap do
182
180
  reset
183
181
  loaded!
@@ -238,14 +236,20 @@ module ActiveFedora
238
236
  def count(options = {})
239
237
  @reflection.klass.count(:conditions => @counter_query)
240
238
  end
241
-
239
+
240
+ # Sets the target of this proxy to <tt>\target</tt>, and the \loaded flag to +true+.
241
+ def target=(target)
242
+ @target = [target]
243
+ loaded!
244
+ end
245
+
242
246
  def load_target
243
247
  if find_target?
244
248
  targets = []
245
249
 
246
250
  begin
247
251
  targets = find_target
248
- rescue ObjectNotFoundError => e
252
+ rescue ObjectNotFoundError, Ldp::Gone => e
249
253
  ActiveFedora::Base.logger.error "Solr and Fedora may be out of sync:\n" + e.message if ActiveFedora::Base.logger
250
254
  reset
251
255
  end
@@ -260,7 +264,9 @@ module ActiveFedora
260
264
  def find_target
261
265
  # TODO: don't reify, just store the solr results and lazily reify.
262
266
  # For now, we set a hard limit of 1000 results.
263
- return ActiveFedora::SolrService.reify_solr_results(load_from_solr(rows: 1000))
267
+ records = ActiveFedora::SolrService.reify_solr_results(load_from_solr(rows: 1000))
268
+ records.each { |record| set_inverse_instance(record) }
269
+ records
264
270
  end
265
271
 
266
272
  def merge_target_lists(loaded, existing)
@@ -291,23 +297,9 @@ module ActiveFedora
291
297
  SolrService.query(@finder_query, solr_opts.merge(opts))
292
298
  end
293
299
 
294
- def add_record_to_target_with_callbacks(record)
295
- callback(:before_add, record)
296
- yield(record) if block_given?
297
- @target ||= [] unless loaded?
298
- if index = @target.index(record)
299
- @target[index] = record
300
- else
301
- @target << record
302
- end
303
- callback(:after_add, record)
304
- # set_inverse_instance(record, @owner)
305
- record
306
- end
307
-
308
- def add_to_target(record)
300
+ def add_to_target(record, skip_callbacks = false)
309
301
  # transaction do
310
- callback(:before_add, record)
302
+ callback(:before_add, record) unless skip_callbacks
311
303
  yield(record) if block_given?
312
304
 
313
305
  if @reflection.options[:uniq] && index = @target.index(record)
@@ -316,7 +308,7 @@ module ActiveFedora
316
308
  @target << record
317
309
  end
318
310
 
319
- callback(:after_add, record)
311
+ callback(:after_add, record) unless skip_callbacks
320
312
  set_inverse_instance(record)
321
313
  # end
322
314
 
@@ -339,80 +331,64 @@ module ActiveFedora
339
331
 
340
332
  def construct_query
341
333
 
342
- clauses = {find_predicate => @owner.internal_uri}
334
+ #TODO use primary_key instead of id
335
+ clauses = {find_predicate.to_s => @owner.id}
343
336
  clauses[:has_model] = @reflection.class_name.constantize.to_class_uri if @reflection.class_name && @reflection.class_name != 'ActiveFedora::Base'
344
337
  @counter_query = @finder_query = ActiveFedora::SolrService.construct_query_for_rel(clauses)
345
338
  end
346
339
 
347
340
 
348
- private
349
-
350
- # Assigns the ID of the owner to the corresponding foreign key in +record+.
351
- # If the association is polymorphic the type of the owner is also set.
352
- def set_belongs_to_association_for(record)
353
- unless @owner.new_record?
354
- record.add_relationship(find_predicate, @owner)
355
- end
356
- end
341
+ private
357
342
 
358
343
  def find_predicate
359
- if @reflection.options[:property]
360
- @reflection.options[:property]
344
+ if @reflection.options[:predicate]
345
+ reflection.predicate.to_s
361
346
  elsif @reflection.class_name && @reflection.class_name != 'ActiveFedora::Base' && @reflection.macro != :has_and_belongs_to_many
362
347
  inverse_relation = @owner.class.to_s.underscore.to_sym
363
348
  begin
364
- find_class_for_relation(@reflection.class_name.constantize)
349
+ find_class_for_relation(@reflection.class_name.constantize)
365
350
  rescue NameError
366
- raise "No :property attribute was set or could be inferred for #{@reflection.macro} #{@reflection.name.inspect} on #{@owner.class}"
351
+ raise "No :predicate attribute was set or could be inferred for #{@reflection.macro} #{@reflection.name.inspect} on #{@owner.class}"
367
352
  end
368
353
  end
369
354
  end
370
355
 
371
356
  def find_class_for_relation(klass, inverse_relation=@owner.class.to_s.underscore.to_sym)
372
- raise "Unable to lookup the :property attribute for #{@reflection.macro} #{@reflection.name.inspect} on #{@owner.class} because #{klass} specifies \"class_name: 'ActiveFedora::Base'\". Either specify a specific class_name in #{klass} or set :property in the #{@reflection.macro} declaration on #{@owner.class}" if inverse_relation == :'active_fedora/base'
357
+ raise "Unable to lookup the :predicate attribute for #{@reflection.macro} #{@reflection.name.inspect} on #{@owner.class} because #{klass} specifies \"class_name: 'ActiveFedora::Base'\". Either specify a specific class_name in #{klass} or set :predicate in the #{@reflection.macro} declaration on #{@owner.class}" if inverse_relation == :'active_fedora/base'
373
358
  if klass.reflections.key?(inverse_relation)
374
359
  # Try it singular
375
- return klass.reflections[inverse_relation].options[:property]
360
+ return klass.reflections[inverse_relation].predicate
376
361
  elsif klass.reflections.key?(inverse_relation.to_s.pluralize.to_sym)
377
- # Try it plural
378
- return klass.reflections[inverse_relation.to_s.pluralize.to_sym].options[:property]
362
+ # Try it plural
363
+ return klass.reflections[inverse_relation.to_s.pluralize.to_sym].predicate
379
364
  end
380
365
  find_class_for_relation(klass, @owner.class.superclass.to_s.underscore.to_sym)
381
366
  end
382
367
 
383
- def create_record(attrs)
384
- attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
368
+ def create_record(attributes, raise = false)
369
+ attributes.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
385
370
  ensure_owner_is_not_new
386
- record = @reflection.klass.create do
387
- @reflection.build_association(attrs)
388
- end
389
- set_belongs_to_association_for(record)
390
- if block_given?
391
- add_record_to_target_with_callbacks(record) { |*block_args| yield(*block_args) }
392
- else
393
- add_record_to_target_with_callbacks(record)
371
+
372
+ add_to_target(build_record(attributes)) do |record|
373
+ yield(record) if block_given?
374
+ insert_record(record, true, raise)
394
375
  end
395
376
  end
396
377
 
397
- def build_record(attrs)
398
- #attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
399
- record = @reflection.build_association(attrs)
400
- if block_given?
401
- add_record_to_target_with_callbacks(record) { |*block_args| yield(*block_args) }
402
- else
403
- add_record_to_target_with_callbacks(record)
404
- end
378
+ def create_scope
379
+ scope.scope_for_create.stringify_keys
405
380
  end
406
381
 
407
382
  def delete_or_destroy(records, method)
408
383
  records = records.flatten
409
384
  records.each { |record| raise_on_type_mismatch(record) }
410
- existing_records = records.reject { |r| r.new_record? }
385
+ existing_records = records.select { |r| r.persisted? }
411
386
 
412
387
  records.each { |record| callback(:before_remove, record) }
413
-
414
388
  delete_records(existing_records, method) if existing_records.any?
415
- records.each { |record| target.delete(record) }
389
+ records.each do |record|
390
+ target.delete(record)
391
+ end
416
392
 
417
393
  records.each { |record| callback(:after_remove, record) }
418
394
  end
@@ -447,9 +423,10 @@ module ActiveFedora
447
423
 
448
424
  #collection = fetch_first_or_last_using_find?(args) ? scoped : load_target
449
425
  collection = load_target
450
- collection.send(type, *args)
426
+ collection.send(type, *args).tap do |record|
427
+ set_inverse_instance record if record.is_a? ActiveFedora::Base
428
+ end
451
429
  end
452
-
453
430
  end
454
431
  end
455
432
  end