iqvoc 4.0.8 → 4.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. data/CHANGELOG.md +11 -0
  2. data/Gemfile +5 -1
  3. data/Gemfile.lock +35 -18
  4. data/README.md +3 -2
  5. data/app/assets/stylesheets/iqvoc/components.css.scss +0 -6
  6. data/app/controllers/collections_controller.rb +30 -17
  7. data/app/controllers/concepts/alphabetical_controller.rb +15 -9
  8. data/app/{models/collection/member/concept.rb → controllers/concepts/expired_controller.rb} +13 -15
  9. data/app/controllers/concepts/hierarchical_controller.rb +3 -0
  10. data/app/controllers/concepts_controller.rb +2 -3
  11. data/app/controllers/instance_configuration_controller.rb +5 -6
  12. data/app/controllers/search_results_controller.rb +1 -2
  13. data/app/helpers/application_helper.rb +1 -5
  14. data/app/helpers/concepts_helper.rb +1 -1
  15. data/app/helpers/rdf_helper.rb +1 -1
  16. data/app/helpers/widget_helper.rb +3 -3
  17. data/app/models/collection/base.rb +64 -46
  18. data/app/models/collection/member/base.rb +12 -0
  19. data/app/models/collection/member/skos/base.rb +13 -12
  20. data/app/models/collection/skos/base.rb +1 -1
  21. data/app/models/collection/{member/collection.rb → skos/unordered.rb} +1 -16
  22. data/app/models/collection/unordered.rb +7 -0
  23. data/app/models/concept/base.rb +26 -107
  24. data/app/models/concept/relation/base.rb +4 -0
  25. data/app/models/concept/relation/skos/base.rb +17 -7
  26. data/app/models/concept/skos/base.rb +10 -1
  27. data/app/models/concept/skos/scheme.rb +1 -1
  28. data/app/models/concept/validations.rb +117 -0
  29. data/app/models/label/base.rb +4 -3
  30. data/app/models/labeling/skos/base.rb +24 -13
  31. data/app/models/match/skos/base.rb +24 -5
  32. data/app/models/note/skos/base.rb +17 -14
  33. data/app/views/collections/_form.html.erb +2 -2
  34. data/app/views/collections/_header.html.erb +2 -2
  35. data/app/views/collections/_sidebar.html.erb +3 -3
  36. data/app/views/collections/index.html.erb +1 -1
  37. data/app/views/collections/show.html.erb +1 -1
  38. data/app/views/collections/show.iqrdf +1 -1
  39. data/app/views/concepts/alphabetical/index.html.erb +1 -1
  40. data/app/views/concepts/expired/index.html.erb +16 -0
  41. data/app/views/concepts/notifications/_referenced_concepts.html.erb +1 -1
  42. data/app/views/concepts/sidebars/_plural.html.erb +4 -0
  43. data/app/views/dashboard/index.html.erb +1 -1
  44. data/app/views/layouts/_controls.html.erb +25 -24
  45. data/app/views/layouts/_navigation.html.erb +1 -1
  46. data/app/views/layouts/application.html.erb +0 -6
  47. data/app/views/partials/concept/_edit_link_base.html.erb +2 -1
  48. data/app/views/partials/labeling/skos/_base.html.erb +1 -2
  49. data/app/views/partials/note/_edit_base.html.erb +1 -1
  50. data/app/views/partials/note/skos/_edit_change_note.html.erb +1 -1
  51. data/app/views/rdf/scheme.iqrdf +1 -1
  52. data/app/views/search_results/_header.html.erb +2 -2
  53. data/app/views/search_results/_sidebar.html.erb +2 -2
  54. data/app/views/search_results/index.html.erb +1 -1
  55. data/app/views/triplestore_sync/index.html.erb +2 -2
  56. data/config/locales/de.yml +9 -2
  57. data/config/locales/en.yml +11 -4
  58. data/config/locales/pt.yml +8 -3
  59. data/config/routes.rb +15 -6
  60. data/db/migrate/20130227145825_fix_collection_type.rb +10 -0
  61. data/db/schema.rb +1 -1
  62. data/lib/generators/app/template.rb +20 -0
  63. data/lib/iqvoc/configuration/collection.rb +5 -5
  64. data/lib/iqvoc/configuration/concept.rb +7 -7
  65. data/lib/iqvoc/configuration/core.rb +11 -10
  66. data/lib/iqvoc/controller_extensions.rb +2 -5
  67. data/lib/iqvoc/inline_data_helper.rb +25 -3
  68. data/lib/iqvoc/instance_configuration.rb +1 -1
  69. data/lib/iqvoc/rdfapi.rb +56 -0
  70. data/lib/iqvoc/skos_importer.rb +88 -40
  71. data/lib/iqvoc/version.rb +1 -1
  72. data/lib/multi_logger.rb +38 -0
  73. data/lib/tasks/importer.rake +6 -1
  74. data/test/integration/browse_concepts_and_labels_test.rb +16 -0
  75. data/test/integration/instance_configuration_test.rb +5 -5
  76. data/test/integration/search_test.rb +18 -17
  77. data/test/unit/concept_test.rb +53 -4
  78. data/test/unit/inline_data_test.rb +61 -0
  79. data/test/unit/origin_test.rb +1 -1
  80. data/test/unit/rdfapi_test.rb +83 -0
  81. data/test/unit/skos_import_test.rb +1 -1
  82. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  83. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_flat_55_fbec88_40x100.png +0 -0
  84. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  85. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  86. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  87. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  88. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  89. data/{public/assets/jquery-ui → vendor/assets/images}/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  90. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_217bc0_256x240.png +0 -0
  91. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_2e83ff_256x240.png +0 -0
  92. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_469bdd_256x240.png +0 -0
  93. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_6da8d5_256x240.png +0 -0
  94. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_cd0a0a_256x240.png +0 -0
  95. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_d8e7f3_256x240.png +0 -0
  96. data/{public/assets/jquery-ui → vendor/assets/images}/ui-icons_f9bd01_256x240.png +0 -0
  97. data/vendor/assets/stylesheets/{jquery-ui-1.8.23.custom.css → jquery-ui-1.8.23.custom.css.scss} +17 -17
  98. metadata +29 -131
  99. data/app/controllers/collections/hierarchical_controller.rb +0 -44
  100. data/public/assets/ajax-loader-dada1fbb71d7fb80d8dde7a031ae6cd0.gif +0 -0
  101. data/public/assets/ajax-loader.gif +0 -0
  102. data/public/assets/arrow_down-07c5dea12928d65fcc31c08279366170.gif +0 -0
  103. data/public/assets/arrow_down.gif +0 -0
  104. data/public/assets/arrow_up-51ede92c113b9a870e7a306907360ba8.gif +0 -0
  105. data/public/assets/arrow_up.gif +0 -0
  106. data/public/assets/bootstrap/bootstrap-2012a68e8267282c0a2c177d7005ae6d.css +0 -9
  107. data/public/assets/bootstrap/bootstrap-2012a68e8267282c0a2c177d7005ae6d.css.gz +0 -0
  108. data/public/assets/bootstrap/bootstrap-35fd77cdf54a8cb63a39d8d0cea7a746.js +0 -19
  109. data/public/assets/bootstrap/bootstrap-35fd77cdf54a8cb63a39d8d0cea7a746.js.gz +0 -0
  110. data/public/assets/bootstrap/bootstrap-responsive-609b376f4bb032588c054b563d4bca1f.css +0 -9
  111. data/public/assets/bootstrap/bootstrap-responsive-609b376f4bb032588c054b563d4bca1f.css.gz +0 -0
  112. data/public/assets/bootstrap/bootstrap-responsive.css +0 -9
  113. data/public/assets/bootstrap/bootstrap-responsive.css.gz +0 -0
  114. data/public/assets/bootstrap/bootstrap.css +0 -9
  115. data/public/assets/bootstrap/bootstrap.css.gz +0 -0
  116. data/public/assets/bootstrap/bootstrap.js +0 -19
  117. data/public/assets/bootstrap/bootstrap.js.gz +0 -0
  118. data/public/assets/bootstrap/glyphicons-halflings-0e7ff93d8f48fe1f5f762e4312e78da7.png +0 -0
  119. data/public/assets/bootstrap/glyphicons-halflings-white-ef3d5b8d6a297804352b4a46fdb5466d.png +0 -0
  120. data/public/assets/bootstrap/glyphicons-halflings-white.png +0 -0
  121. data/public/assets/bootstrap/glyphicons-halflings.png +0 -0
  122. data/public/assets/file-58ce0b58f19dfe871b25270e98cff66c.gif +0 -0
  123. data/public/assets/file.gif +0 -0
  124. data/public/assets/folder-5c5b1fd2f1ece710f9159f05cc2aaaa8.gif +0 -0
  125. data/public/assets/folder-closed-8b61fc55011d534f0216c1150994f229.gif +0 -0
  126. data/public/assets/folder-closed.gif +0 -0
  127. data/public/assets/folder.gif +0 -0
  128. data/public/assets/html5-05e1be9157c8366db72fb7a1bcc8daff.js +0 -3
  129. data/public/assets/html5-05e1be9157c8366db72fb7a1bcc8daff.js.gz +0 -0
  130. data/public/assets/html5.js +0 -3
  131. data/public/assets/html5.js.gz +0 -0
  132. data/public/assets/iqvoc/ie_fixes-6a106c21d979ccdd1f6bf1cb129a0e69.css +0 -1
  133. data/public/assets/iqvoc/ie_fixes-6a106c21d979ccdd1f6bf1cb129a0e69.css.gz +0 -0
  134. data/public/assets/iqvoc/ie_fixes.css +0 -1
  135. data/public/assets/iqvoc/ie_fixes.css.gz +0 -0
  136. data/public/assets/iqvoc_logo-316859a511c646918fe75e92fa0bf6ac.png +0 -0
  137. data/public/assets/iqvoc_logo.png +0 -0
  138. data/public/assets/jquery-ui/ui-bg_flat_0_aaaaaa_40x100-a1eb3e0764573ed4b261ca742ed96ac3.png +0 -0
  139. data/public/assets/jquery-ui/ui-bg_flat_55_fbec88_40x100-439ee8e6c8ce855f43ed4d7b90684720.png +0 -0
  140. data/public/assets/jquery-ui/ui-bg_glass_75_d0e5f5_1x400-9357836db77954d0d8c5feb259635223.png +0 -0
  141. data/public/assets/jquery-ui/ui-bg_glass_85_dfeffc_1x400-7beb11d1590fb2fb1ef5c754100a078a.png +0 -0
  142. data/public/assets/jquery-ui/ui-bg_glass_95_fef1ec_1x400-c723e9a2b50006c6054836a10b76bb84.png +0 -0
  143. data/public/assets/jquery-ui/ui-bg_gloss-wave_55_5c9ccc_500x100-cb26f48ac4912c23ce301c69c474d306.png +0 -0
  144. data/public/assets/jquery-ui/ui-bg_inset-hard_100_f5f8f9_1x100-519299e2aa31bffdd4fed34b4fac603d.png +0 -0
  145. data/public/assets/jquery-ui/ui-bg_inset-hard_100_fcfdfd_1x100-27e08524d3d56bb59e354435b663c3ac.png +0 -0
  146. data/public/assets/jquery-ui/ui-icons_217bc0_256x240-ed26778199d8722ae064038a1e841bc8.png +0 -0
  147. data/public/assets/jquery-ui/ui-icons_2e83ff_256x240-94086d0ce953eb0887ab1b8140903af9.png +0 -0
  148. data/public/assets/jquery-ui/ui-icons_469bdd_256x240-1c055f2d65517ef8faf1d1999c8ac2fa.png +0 -0
  149. data/public/assets/jquery-ui/ui-icons_6da8d5_256x240-8f5b417c5604f1b7b5965c98754c33b9.png +0 -0
  150. data/public/assets/jquery-ui/ui-icons_cd0a0a_256x240-8b44e266bdc1f57f1393579591f89222.png +0 -0
  151. data/public/assets/jquery-ui/ui-icons_d8e7f3_256x240-1b415e411069df902e6f417cc014172c.png +0 -0
  152. data/public/assets/jquery-ui/ui-icons_f9bd01_256x240-4553d0576c0498ca4c776aa77aa80833.png +0 -0
  153. data/public/assets/json2-b08b7b9af3e715f42c088ac728f62a2b.js +0 -157
  154. data/public/assets/json2-b08b7b9af3e715f42c088ac728f62a2b.js.gz +0 -0
  155. data/public/assets/json2.js +0 -157
  156. data/public/assets/json2.js.gz +0 -0
  157. data/public/assets/manifest-3ce8edde69d5d291841ef7c49daaa9cb.js +0 -21
  158. data/public/assets/manifest-3ce8edde69d5d291841ef7c49daaa9cb.js.gz +0 -0
  159. data/public/assets/manifest-c0eca563fd9f16907d302af9a2dcae6b.css +0 -51
  160. data/public/assets/manifest-c0eca563fd9f16907d302af9a2dcae6b.css.gz +0 -0
  161. data/public/assets/manifest.css +0 -51
  162. data/public/assets/manifest.css.gz +0 -0
  163. data/public/assets/manifest.js +0 -21
  164. data/public/assets/manifest.js.gz +0 -0
  165. data/public/assets/manifest.yml +0 -47
  166. data/public/assets/minus-1d0fae0720bab52bd98598218e8345c0.gif +0 -0
  167. data/public/assets/minus.gif +0 -0
  168. data/public/assets/plus-1a29e46532f839ed9c977ef4613d079f.gif +0 -0
  169. data/public/assets/plus.gif +0 -0
  170. data/public/assets/spinner_16x16-17dcf941457ae4e702f4600e714b21c1.gif +0 -0
  171. data/public/assets/spinner_16x16.gif +0 -0
  172. data/public/assets/spinner_24x24-78c707c1921b93962ea5edd7f4a74134.gif +0 -0
  173. data/public/assets/spinner_24x24.gif +0 -0
  174. data/public/assets/treeview-black-c46d96020e5d79c652af0fb0c6656384.gif +0 -0
  175. data/public/assets/treeview-black-line-0903c58efd34c3203d132e6f873049f6.gif +0 -0
  176. data/public/assets/treeview-black-line.gif +0 -0
  177. data/public/assets/treeview-black.gif +0 -0
  178. data/public/assets/treeview-default-ee6298d311205d21dc57c01c0696df70.gif +0 -0
  179. data/public/assets/treeview-default-line-2c4106cfd4d322c6e6565f80702c27cb.gif +0 -0
  180. data/public/assets/treeview-default-line.gif +0 -0
  181. data/public/assets/treeview-default.gif +0 -0
  182. data/public/assets/treeview-famfamfam-20dfef13cd5fd1e08fb61ee68eb9d3fa.gif +0 -0
  183. data/public/assets/treeview-famfamfam-line-a02cce2b80977e066df83137aae71fa8.gif +0 -0
  184. data/public/assets/treeview-famfamfam-line.gif +0 -0
  185. data/public/assets/treeview-famfamfam.gif +0 -0
  186. data/public/assets/treeview-gray-01bfdcd116e081e23daf13024fd3e4e0.gif +0 -0
  187. data/public/assets/treeview-gray-line-029b3a7b92ed10ea6c4b6289cb9fa0e3.gif +0 -0
  188. data/public/assets/treeview-gray-line.gif +0 -0
  189. data/public/assets/treeview-gray.gif +0 -0
  190. data/public/assets/treeview-red-2a5abbce598d05c864d845998381eef6.gif +0 -0
  191. data/public/assets/treeview-red-line-f51e6c30aa3b0ff856900ba85d769f1c.gif +0 -0
  192. data/public/assets/treeview-red-line.gif +0 -0
  193. data/public/assets/treeview-red.gif +0 -0
  194. data/vendor/assets/images/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  195. data/vendor/assets/images/jquery-ui/ui-bg_flat_55_fbec88_40x100.png +0 -0
  196. data/vendor/assets/images/jquery-ui/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  197. data/vendor/assets/images/jquery-ui/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  198. data/vendor/assets/images/jquery-ui/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  199. data/vendor/assets/images/jquery-ui/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  200. data/vendor/assets/images/jquery-ui/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  201. data/vendor/assets/images/jquery-ui/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  202. data/vendor/assets/images/jquery-ui/ui-icons_217bc0_256x240.png +0 -0
  203. data/vendor/assets/images/jquery-ui/ui-icons_2e83ff_256x240.png +0 -0
  204. data/vendor/assets/images/jquery-ui/ui-icons_469bdd_256x240.png +0 -0
  205. data/vendor/assets/images/jquery-ui/ui-icons_6da8d5_256x240.png +0 -0
  206. data/vendor/assets/images/jquery-ui/ui-icons_cd0a0a_256x240.png +0 -0
  207. data/vendor/assets/images/jquery-ui/ui-icons_d8e7f3_256x240.png +0 -0
  208. data/vendor/assets/images/jquery-ui/ui-icons_f9bd01_256x240.png +0 -0
  209. data/vendor/assets/javascripts/json2.js +0 -487
@@ -25,4 +25,16 @@ class Collection::Member::Base < ActiveRecord::Base
25
25
  belongs_to :collection, :class_name => 'Collection::Base'
26
26
  belongs_to :target, :class_name => 'Concept::Base'
27
27
 
28
+ def self.view_section(obj)
29
+ "main"
30
+ end
31
+
32
+ def self.view_section_sort_key(obj)
33
+ 100
34
+ end
35
+
36
+ def self.partial_name(obj)
37
+ "partials/collection/member"
38
+ end
39
+
28
40
  end
@@ -16,22 +16,23 @@
16
16
 
17
17
  class Collection::Member::SKOS::Base < Collection::Member::Base
18
18
 
19
- self.rdf_namespace = "skos"
20
- self.rdf_predicate = "member"
19
+ self.rdf_namespace = 'skos'
20
+ self.rdf_predicate = 'member'
21
21
 
22
- def self.build_from_rdf(subject, predicate, object)
23
- raise "Labeling::SKOS::Base#build_from_rdf: Subject (#{subject}) must be a Collection." unless subject.is_a?(Collection::Base)
24
- raise "Labeling::SKOS::Base#build_from_rdf: Object (#{object}) must be a Collection or Concept." unless object.is_a?(Collection::Base) or object.is_a?(Concept::Base)
22
+ def self.build_from_rdf(rdf_subject, rdf_predicate, rdf_object)
23
+ raise "#{self.name}#build_from_rdf: Subject (#{rdf_subject}) must be a Collection." unless rdf_subject.is_a?(Collection::Base)
24
+ raise "#{self.name}#build_from_rdf: Object (#{rdf_object}) must be a Collection or Concept." unless rdf_object.is_a?(Collection::Base) or rdf_object.is_a?(Concept::Base)
25
25
 
26
- if subject.send(:members).select{|rel| rel.collection_id == subject.id || rel.target == object}.empty?
27
- subject.send(:members) << self.new(:target => object)
28
- if object.is_a?(Collection::Base)
29
- subject.send(:subcollections) << object
30
- end
26
+ member_instance = rdf_subject.members.select{|rel| rel.target == rdf_object}.first
27
+ if member_instance.nil?
28
+ predicate_class = Iqvoc::RDFAPI::PREDICATE_DICTIONARY[rdf_predicate] || self
29
+ member_instance = predicate_class.new(:target => rdf_object)
30
+ rdf_subject.members << member_instance
31
31
  end
32
32
 
33
- if object.send(:collections).select{|coll| coll.id == subject.id}.empty?
34
- object.send(:collections) << subject
33
+ if rdf_object.collections.select{|coll| coll.id == rdf_subject.id}.empty?
34
+ rdf_object.collections << rdf_subject
35
35
  end
36
+ member_instance
36
37
  end
37
38
  end
@@ -19,7 +19,7 @@ class Collection::SKOS::Base < Collection::Base
19
19
  self.rdf_namespace = "skos"
20
20
  self.rdf_class = "Collection"
21
21
 
22
- def build_rdf_subject(document, controller, &block)
22
+ def build_rdf_subject(&block)
23
23
  ns = IqRdf::Namespace.find_namespace_class(self.rdf_namespace)
24
24
  raise "Namespace '#{base_namespace}' is not defined in IqRdf document." unless ns
25
25
  subject = IqRdf.build_uri(self.origin, ns.build_uri(self.rdf_class), &block)
@@ -14,20 +14,5 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- class Collection::Member::Collection < Collection::Member::Base
18
-
19
- belongs_to :subcollection, :class_name => 'Collection::Base', :foreign_key => 'target_id'
20
-
21
- def self.view_section(obj)
22
- "main"
23
- end
24
-
25
- def self.view_section_sort_key(obj)
26
- 100
27
- end
28
-
29
- def self.partial_name(obj)
30
- "partials/collection/member"
31
- end
32
-
17
+ class Collection::SKOS::Unordered < Collection::SKOS::Base
33
18
  end
@@ -14,5 +14,12 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
+
17
18
  class Collection::Unordered < Collection::SKOS::Base
19
+
20
+ def initialize(*args)
21
+ ActiveSupport::Deprecation.warn("Collection::Unordered is deprecated. Use Collection::SKOS::Unordered instead.")
22
+ super
23
+ end
24
+
18
25
  end
@@ -27,19 +27,7 @@ class Concept::Base < ActiveRecord::Base
27
27
  self.rdf_namespace = nil
28
28
  self.rdf_class = nil
29
29
 
30
- # ********** Validations
31
-
32
- validates :origin, :presence => true, :on => :update
33
-
34
- validate :ensure_distinct_versions, :on => :create
35
-
36
- validate :ensure_a_pref_label_in_the_primary_thesaurus_language,
37
- :on => :update
38
-
39
- validate :ensure_no_pref_labels_share_the_same_language
40
- validate :ensure_exclusive_top_term
41
- validate :ensure_rooted_top_terms
42
- validate :ensure_valid_rank_for_ranked_relations
30
+ include Concept::Validations
43
31
 
44
32
  Iqvoc::Concept.include_modules.each do |mod|
45
33
  include mod
@@ -63,9 +51,10 @@ class Concept::Base < ActiveRecord::Base
63
51
  labeling_class = reflection && reflection.class_name && reflection.class_name.constantize
64
52
  if labeling_class && labeling_class < Labeling::Base
65
53
  self.send(relation_name).all.map(&:destroy)
66
- lang_values = {nil => lang_values.first} if lang_values.is_a?(Array) # For language = nil: <input name=bla[labeling_class][]> => Results in an Array!
67
- lang_values.each do |lang, values|
68
- values.split(Iqvoc::InlineDataHelper::Splitter).each do |value|
54
+ lang_values = { nil => lang_values.first } if lang_values.is_a?(Array) # For language = nil: <input name=bla[labeling_class][]> => Results in an Array! -- XXX: obsolete/dupe (cf `labelings_by_text=`)?
55
+ lang_values.each do |lang, inline_values|
56
+ lang = nil if lang.to_s == 'none'
57
+ Iqvoc::InlineDataHelper.parse_inline_values(inline_values).each do |value|
69
58
  value.squish!
70
59
  self.send(relation_name).build(:target => labeling_class.label_class.new(:value => value, :language => lang)) unless value.blank?
71
60
  end
@@ -85,7 +74,7 @@ class Concept::Base < ActiveRecord::Base
85
74
  # rankable: {'relation_name' => ['origin1:100', 'origin2:90']}
86
75
  (@concept_relations_by_id ||= {}).each do |relation_name, new_origins|
87
76
  # Split comma-separated origins and clean up parameter strings
88
- new_origins = new_origins.split(Iqvoc::InlineDataHelper::Splitter).map(&:squish)
77
+ new_origins = new_origins.split(Iqvoc::InlineDataHelper::SPLITTER).map(&:squish)
89
78
 
90
79
  # Extract embedded ranks (if any) from origin strings (e.g. "origin1:100")
91
80
  # => { 'origin1' => nil, 'origin2' => 90 }
@@ -139,7 +128,7 @@ class Concept::Base < ActiveRecord::Base
139
128
  has_many :matches, :foreign_key => 'concept_id', :class_name => "Match::Base", :dependent => :destroy
140
129
  include_to_deep_cloning(:matches)
141
130
 
142
- has_many :collection_members, :foreign_key => 'target_id', :class_name => "Collection::Member::Concept", :dependent => :destroy
131
+ has_many :collection_members, :foreign_key => 'target_id', :class_name => "Collection::Member::Base", :dependent => :destroy
143
132
  has_many :collections, :through => :collection_members, :class_name => Iqvoc::Collection.base_class_name
144
133
  include_to_deep_cloning(:collection_members)
145
134
 
@@ -300,18 +289,22 @@ class Concept::Base < ActiveRecord::Base
300
289
  def labelings_by_text=(hash)
301
290
  @labelings_by_text = hash
302
291
 
303
- # For language = nil: <input name=bla[labeling_class][]> => Results in an Array!
304
- @labelings_by_text.each do |relation_name, array_or_hash|
305
- @labelings_by_text[relation_name] = {nil => array_or_hash.first} if array_or_hash.is_a?(Array)
292
+ @labelings_by_text.each do |relation_name, labels_by_lang|
293
+ # if `language` is `nil`, the respective HTML form field returns an array
294
+ # instead of a hash (`<input name=bla[labeling_class][]>`)
295
+ if labels_by_lang.is_a?(Array)
296
+ @labelings_by_text[relation_name] = { nil => labels_by_lang.first }
297
+ end
306
298
  end
307
299
 
308
300
  @labelings_by_text
309
301
  end
310
302
 
311
303
  def labelings_by_text(relation_name, language)
312
- (@labelings_by_text && @labelings_by_text[relation_name] && @labelings_by_text[relation_name][language]) ||
313
- self.send(relation_name).by_label_language(language).
314
- map { |l| l.target.value }.join(Iqvoc::InlineDataHelper::Joiner)
304
+ (@labelings_by_text && @labelings_by_text[relation_name] &&
305
+ @labelings_by_text[relation_name][language]) ||
306
+ Iqvoc::InlineDataHelper.generate_inline_values(self.send(relation_name).
307
+ by_label_language(language).map { |l| l.target.value })
315
308
  end
316
309
 
317
310
  def concept_relations_by_id=(hash)
@@ -321,7 +314,7 @@ class Concept::Base < ActiveRecord::Base
321
314
  def concept_relations_by_id(relation_name)
322
315
  (@concept_relations_by_id && @concept_relations_by_id[relation_name]) ||
323
316
  self.send(relation_name).map { |l| l.target.origin }.
324
- join(Iqvoc::InlineDataHelper::Joiner)
317
+ join(Iqvoc::InlineDataHelper::JOINER)
325
318
  end
326
319
 
327
320
  def concept_relations_by_id_and_rank(relation_name)
@@ -335,12 +328,12 @@ class Concept::Base < ActiveRecord::Base
335
328
  # If no prefLabel for the requested language exists, a new label will be returned
336
329
  # (if you modify it, don't forget to save it afterwards!)
337
330
  def pref_label
338
- lang = I18n.locale.to_s
331
+ lang = I18n.locale.to_s == "none" ? nil : I18n.locale.to_s
339
332
  @cached_pref_labels ||= pref_labels.each_with_object({}) do |label, hash|
340
333
  if hash[label.language]
341
334
  Rails.logger.warn("Two pref_labels (#{hash[label.language]}, #{label}) for one language (#{label.language}). Taking the second one.")
342
335
  end
343
- hash[label.language.to_s] = label
336
+ hash[label.language] = label
344
337
  end
345
338
  if @cached_pref_labels[lang].nil?
346
339
  # Fallback to the main language
@@ -354,12 +347,16 @@ class Concept::Base < ActiveRecord::Base
354
347
  def labels_for_labeling_class_and_language(labeling_class, lang = :en, only_published = true)
355
348
  # Convert lang to string in case it's not nil.
356
349
  # nil values play their own role for labels without a language.
357
- lang = lang.to_s unless lang.nil?
350
+ if lang == "none"
351
+ lang = nil
352
+ elsif lang
353
+ lang = lang.to_s
354
+ end
358
355
  labeling_class = labeling_class.name if labeling_class < ActiveRecord::Base # Use the class name string
359
356
  @labels ||= labelings.each_with_object({}) do |labeling, hash|
360
357
  ((hash[labeling.class.name.to_s] ||= {})[labeling.target.language] ||= []) << labeling.target if labeling.target
361
358
  end
362
- return ((@labels && @labels[labeling_class] && @labels[labeling_class][lang]) || []).select{|l| l.published? || !only_published}
359
+ ((@labels && @labels[labeling_class] && @labels[labeling_class][lang]) || []).select{|l| l.published? || !only_published}
363
360
  end
364
361
 
365
362
  def related_concepts_for_relation_class(relation_class, only_published = true)
@@ -416,82 +413,4 @@ class Concept::Base < ActiveRecord::Base
416
413
  }
417
414
  end
418
415
 
419
- # ********** Validation methods
420
-
421
- # validates that
422
- # a) no more than one concept with the same origin already exists
423
- # b) if a concept with the same origin exists, its publication state differs
424
- # from the to-be-saved one's
425
- def ensure_distinct_versions
426
- query = Concept::Base.by_origin(origin)
427
- existing_total = query.count
428
- if existing_total >= 2
429
- errors.add :base, I18n.t("txt.models.concept.version_error")
430
- elsif existing_total == 1
431
- unless (query.published.count == 0 and published?) or
432
- (query.published.count == 1 and not published?)
433
- errors.add :base, I18n.t("txt.models.concept.version_error")
434
- end
435
- end
436
- end
437
-
438
- # top term and broader relations are mutually exclusive
439
- def ensure_exclusive_top_term
440
- if @full_validation
441
- if top_term && broader_relations.any?
442
- errors.add :base, I18n.t("txt.models.concept.top_term_exclusive_error")
443
- end
444
- end
445
- end
446
-
447
- # top terms must never be used as descendants (narrower relation targets)
448
- # NB: for top terms themselves, this is covered by `ensure_exclusive_top_term`
449
- def ensure_rooted_top_terms
450
- if @full_validation
451
- if narrower_relations.includes(:target). # XXX: inefficient?
452
- select { |rel| rel.target && rel.target.top_term? }.any?
453
- errors.add :base, I18n.t("txt.models.concept.top_term_rooted_error")
454
- end
455
- end
456
- end
457
-
458
- def ensure_a_pref_label_in_the_primary_thesaurus_language
459
- if @full_validation
460
- labels = pref_labels.select{|l| l.published?}
461
- if labels.count == 0
462
- errors.add :base, I18n.t("txt.models.concept.no_pref_label_error")
463
- elsif not labels.map(&:language).map(&:to_s).include?(Iqvoc::Concept.pref_labeling_languages.first.to_s)
464
- errors.add :base, I18n.t("txt.models.concept.main_pref_label_language_missing_error")
465
- end
466
- end
467
- end
468
-
469
- def ensure_no_pref_labels_share_the_same_language
470
- # We have many sources a prefLabel can be defined in
471
- pls = pref_labelings.map(&:target) +
472
- send(Iqvoc::Concept.pref_labeling_class_name.to_relation_name).map(&:target) +
473
- labelings.select{|l| l.is_a?(Iqvoc::Concept.pref_labeling_class)}.map(&:target)
474
- languages = {}
475
- pls.compact.each do |pref_label|
476
- lang = pref_label.language.to_s
477
- origin = (pref_label.origin || pref_label.id || pref_label.value).to_s
478
- if (languages.keys.include?(lang) && languages[lang] != origin)
479
- errors.add :pref_labelings, I18n.t("txt.models.concept.pref_labels_with_same_languages_error")
480
- end
481
- languages[lang] = origin
482
- end
483
- end
484
-
485
- def ensure_valid_rank_for_ranked_relations
486
- if @full_validation
487
- relations.each do |relation|
488
- if relation.class.rankable? && !(0..100).include?(relation.rank)
489
- errors.add :base, I18n.t("txt.models.concept.invalid_rank_for_ranked_relations",
490
- :relation => relation.class.model_name.human.downcase,
491
- :relation_target_label => relation.target.pref_label.to_s)
492
- end
493
- end
494
- end
495
- end
496
-
497
416
  end
@@ -71,6 +71,10 @@ class Concept::Relation::Base < ActiveRecord::Base
71
71
  self
72
72
  end
73
73
 
74
+ def self.bidirectional?
75
+ !!self.reverse_relation_class
76
+ end
77
+
74
78
  def self.view_section(obj)
75
79
  "relations"
76
80
  end
@@ -18,15 +18,25 @@ class Concept::Relation::SKOS::Base < Concept::Relation::Base
18
18
 
19
19
  self.rdf_namespace = 'skos'
20
20
 
21
- def self.build_from_rdf(subject, predicate, object)
22
- raise "Labeling::SKOS::Base#build_from_rdf: Subject (#{subject}) must be a Concept." unless subject.is_a?(Concept::Base)
23
- raise "Labeling::SKOS::Base#build_from_rdf: Object (#{object}) must be a Concept." unless object.is_a?(Concept::Base)
21
+ def self.build_from_rdf(rdf_subject, rdf_predicate, rdf_object)
22
+ raise "#{self.name}#build_from_rdf: Subject (#{rdf_subject}) must be a Concept." unless rdf_subject.is_a? Concept::Base
23
+ raise "#{self.name}#build_from_rdf: Object (#{rdf_object}) must be a Concept." unless rdf_object.is_a? Concept::Base
24
24
 
25
- if subject.send(self.name.to_relation_name).select{|rel| rel.target_id == object.id || rel.target == object}.empty?
26
- subject.send(self.name.to_relation_name) << self.new(:target => object)
25
+ relation_class = Iqvoc::RDFAPI::PREDICATE_DICTIONARY[rdf_predicate] || self
26
+
27
+ relation_instance = rdf_subject.send(self.name.to_relation_name).select{|rel| rel.target == rdf_object}
28
+ unless relation_instance
29
+ relation_instance = relation_class.new(:target => rdf_object)
30
+ rdf_subject.send(self.name.to_relation_name) << relation_instance
27
31
  end
28
- if self.reverse_relation_class && object.send(self.reverse_relation_class.name.to_relation_name).select{|rel| rel.target_id == subject.id || rel.target == subject}.empty?
29
- object.send(self.reverse_relation_class.name.to_relation_name) << self.reverse_relation_class.new(:target => subject)
32
+
33
+ if relation_class.bidirectional?
34
+ reverse_class = relation_class.reverse_relation_class
35
+ reverse_collection = rdf_object.send(reverse_class.name.to_relation_name)
36
+ if reverse_collection.select{|rel| rel.target == rdf_subject}.empty?
37
+ reverse_instance = reverse_class.new(:target => rdf_subject)
38
+ reverse_collection << reverse_instance
39
+ end
30
40
  end
31
41
  end
32
42
 
@@ -19,7 +19,7 @@ class Concept::SKOS::Base < Concept::Base
19
19
  self.rdf_namespace = "skos"
20
20
  self.rdf_class = "Concept"
21
21
 
22
- def build_rdf_subject(document, controller, &block)
22
+ def build_rdf_subject(&block)
23
23
  ns = IqRdf::Namespace.find_namespace_class(self.rdf_namespace)
24
24
  raise "Namespace '#{self.rdf_namespace}' is not defined in IqRdf document." unless ns
25
25
  subject = IqRdf.build_uri(self.origin, ns.build_uri(self.rdf_class), &block)
@@ -32,4 +32,13 @@ class Concept::SKOS::Base < Concept::Base
32
32
  return subject
33
33
  end
34
34
 
35
+ # ********** Scopes
36
+ def self.expired(time = Time.now)
37
+ where(arel_table[:expired_at].lt(time))
38
+ end
39
+
40
+ def self.not_expired(time = Time.now)
41
+ col = arel_table[:expired_at]
42
+ where((col.eq(nil)).or(col.gteq(time)))
43
+ end
35
44
  end
@@ -37,7 +37,7 @@ class Concept::SKOS::Scheme
37
37
  :scheme
38
38
  end
39
39
 
40
- def build_rdf_subject(document, controller, &block)
40
+ def build_rdf_subject(&block)
41
41
  ns = IqRdf::Namespace.find_namespace_class(self.class.rdf_namespace.to_sym)
42
42
  raise "Namespace '#{rdf_namespace}' is not defined in IqRdf document." unless ns
43
43
  IqRdf.build_uri(origin, ns.build_uri(self.class.rdf_class), &block)
@@ -0,0 +1,117 @@
1
+ module Concept
2
+ module Validations
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ validates :origin, :presence => true, :on => :update
7
+
8
+ validate :distinct_versions, :on => :create
9
+ validate :pref_label_in_primary_thesaurus_language, :on => :update
10
+ validate :unique_pref_label_language
11
+ validate :exclusive_top_term
12
+ validate :rooted_top_terms
13
+ validate :valid_rank_for_ranked_relations
14
+ validate :unique_pref_label
15
+ end
16
+
17
+ def distinct_versions
18
+ query = Concept::Base.by_origin(origin)
19
+ existing_total = query.count
20
+ if existing_total >= 2
21
+ errors.add :base, I18n.t("txt.models.concept.version_error")
22
+ elsif existing_total == 1
23
+ unless (query.published.count == 0 and published?) or
24
+ (query.published.count == 1 and not published?)
25
+ errors.add :base, I18n.t("txt.models.concept.version_error")
26
+ end
27
+ end
28
+ end
29
+
30
+ # top term and broader relations are mutually exclusive
31
+ def exclusive_top_term
32
+ if @full_validation
33
+ if top_term && broader_relations.any?
34
+ errors.add :base, I18n.t("txt.models.concept.top_term_exclusive_error")
35
+ end
36
+ end
37
+ end
38
+
39
+ # top terms must never be used as descendants (narrower relation targets)
40
+ # NB: for top terms themselves, this is covered by `ensure_exclusive_top_term`
41
+ def rooted_top_terms
42
+ if @full_validation
43
+ if narrower_relations.includes(:target). # XXX: inefficient?
44
+ select { |rel| rel.target && rel.target.top_term? }.any?
45
+ errors.add :base, I18n.t("txt.models.concept.top_term_rooted_error")
46
+ end
47
+ end
48
+ end
49
+
50
+ def pref_label_in_primary_thesaurus_language
51
+ if @full_validation
52
+ labels = pref_labels.select{|l| l.published?}
53
+ if labels.count == 0
54
+ errors.add :base, I18n.t("txt.models.concept.no_pref_label_error")
55
+ elsif not labels.map(&:language).map(&:to_s).include?(Iqvoc::Concept.pref_labeling_languages.first.to_s)
56
+ errors.add :base, I18n.t("txt.models.concept.main_pref_label_language_missing_error")
57
+ end
58
+ end
59
+ end
60
+
61
+ def unique_pref_label_language
62
+ # We have many sources a prefLabel can be defined in
63
+ pls = pref_labelings.map(&:target) +
64
+ send(Iqvoc::Concept.pref_labeling_class_name.to_relation_name).map(&:target) +
65
+ labelings.select{|l| l.is_a?(Iqvoc::Concept.pref_labeling_class)}.map(&:target)
66
+ languages = {}
67
+ pls.compact.each do |pref_label|
68
+ lang = pref_label.language.to_s
69
+ origin = (pref_label.origin || pref_label.id || pref_label.value).to_s
70
+ if (languages.keys.include?(lang) && languages[lang] != origin)
71
+ errors.add :pref_labelings, I18n.t("txt.models.concept.pref_labels_with_same_languages_error")
72
+ end
73
+ languages[lang] = origin
74
+ end
75
+ end
76
+
77
+ def unique_pref_label
78
+ if @full_validation
79
+ # checks if there are any existing pref labels with the same
80
+ # language and value
81
+ conflicting_pref_labels = pref_labels.select do |l|
82
+ Labeling::SKOS::PrefLabel.
83
+ joins(:owner, :target).
84
+ where(:labels => { :value => l.value, :language => l.language }).
85
+ where("labelings.owner_id != ?", id).
86
+ where("concepts.origin != ?", origin).
87
+ any?
88
+ end
89
+
90
+ if conflicting_pref_labels.any?
91
+ if conflicting_pref_labels.one?
92
+ errors.add :base,
93
+ I18n.t("txt.models.concept.pref_label_not_unique",
94
+ :label => conflicting_pref_labels.last.value)
95
+ else
96
+ errors.add :base,
97
+ I18n.t("txt.models.concept.pref_labels_not_unique",
98
+ :label => conflicting_pref_labels.map(&:value).join(", "))
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ def valid_rank_for_ranked_relations
105
+ if @full_validation
106
+ relations.each do |relation|
107
+ if relation.class.rankable? && !(0..100).include?(relation.rank)
108
+ errors.add :base, I18n.t("txt.models.concept.invalid_rank_for_ranked_relations",
109
+ :relation => relation.class.model_name.human.downcase,
110
+ :relation_target_label => relation.target.pref_label.to_s)
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ end
117
+ end
@@ -33,7 +33,8 @@ class Label::Base < ActiveRecord::Base
33
33
  # ********* Scopes
34
34
 
35
35
  def self.by_language(lang_code)
36
- if (lang_code.is_a?(Array) && lang_code.include?(nil))
36
+ lang_code = nil if lang_code.to_s == "none"
37
+ if (lang_code.is_a?(Array) && lang_code.include?("none"))
37
38
  where(arel_table[:language].eq(nil).or(arel_table[:language].in(lang_code.compact)))
38
39
  elsif lang_code.blank?
39
40
  where(arel_table[:language].eq(nil))
@@ -93,8 +94,8 @@ class Label::Base < ActiveRecord::Base
93
94
  end
94
95
 
95
96
  def to_s
96
- if language.to_s != I18n.locale.to_s.strip
97
- value.to_s + " [#{I18n.t("txt.common.translation_missing_for")} '#{I18n.locale.to_s.strip}']"
97
+ if (language.presence || "none") != I18n.locale.to_s
98
+ value.to_s + " [#{I18n.t("txt.common.translation_missing_for")} '#{I18n.locale}']"
98
99
  else
99
100
  value.to_s
100
101
  end
@@ -28,6 +28,14 @@ class Labeling::SKOS::Base < Labeling::Base
28
28
  includes(:target).merge(self.label_class.where(:value => label, :language => language))
29
29
  end
30
30
 
31
+ def self.concept_expired
32
+ includes(:owner).merge(Iqvoc::Concept.base_class.expired)
33
+ end
34
+
35
+ def self.concept_not_expired
36
+ includes(:owner).merge(Iqvoc::Concept.base_class.not_expired)
37
+ end
38
+
31
39
  # ********** Methods
32
40
 
33
41
  def self.label_class
@@ -35,11 +43,11 @@ class Labeling::SKOS::Base < Labeling::Base
35
43
  end
36
44
 
37
45
  def self.partial_name(obj)
38
- "partials/labeling/skos/base"
46
+ 'partials/labeling/skos/base'
39
47
  end
40
48
 
41
49
  def self.edit_partial_name(obj)
42
- "partials/labeling/skos/edit_base"
50
+ 'partials/labeling/skos/edit_base'
43
51
  end
44
52
 
45
53
  def self.single_query(params = {})
@@ -54,10 +62,10 @@ class Labeling::SKOS::Base < Labeling::Base
54
62
  end
55
63
 
56
64
  if params[:collection_origin].present?
57
- collection = Collection::Unordered.where(:origin => params[:collection_origin]).last
65
+ collection = Collection::Base.where(:origin => params[:collection_origin]).last
58
66
  if collection
59
67
  scope = scope.includes(:owner => :collection_members)
60
- scope = scope.where("#{Collection::Member::Base.table_name}.collection_id" => collection)
68
+ scope = scope.where("#{Collection::Member::Base.table_name}.collection_id" => collection.id)
61
69
  else
62
70
  raise "Collection with Origin #{params[:collection_origin]} not found!"
63
71
  end
@@ -65,10 +73,10 @@ class Labeling::SKOS::Base < Labeling::Base
65
73
  scope = scope.includes(:owner)
66
74
 
67
75
  scope = case params[:for]
68
- when "concept"
69
- scope.where("concepts.type" => Iqvoc::Concept.base_class_name).merge(Concept::Base.published)
70
- when "collection"
71
- scope.where("concepts.type" => Iqvoc::Collection.base_class_name)
76
+ when 'concept'
77
+ scope.where('concepts.type' => Iqvoc::Concept.base_class_name).merge(Concept::Base.published)
78
+ when 'collection'
79
+ scope.where('concepts.type' => Iqvoc::Collection.base_class_name)
72
80
  else
73
81
  # no additional conditions
74
82
  scope
@@ -81,18 +89,21 @@ class Labeling::SKOS::Base < Labeling::Base
81
89
  'partials/labeling/skos/search_result'
82
90
  end
83
91
 
84
- def self.build_from_rdf(subject, predicate, object)
85
- raise "Labeling::SKOS::Base#build_from_rdf: Subject (#{subject}) must be a Concept." unless subject.is_a?(Concept::Base)
86
- raise "Labeling::SKOS::Base#build_from_rdf: Object (#{object}) must be a string literal" unless object =~ /^"(.+)"(@(.+))?$/
92
+ def self.build_from_rdf(rdf_subject, rdf_predicate, rdf_object)
93
+ raise "#{self.name}#build_from_rdf: Subject (#{rdf_subject}) must be a Concept." unless rdf_subject.is_a?(Concept::Base)
94
+ raise "#{self.name}#build_from_rdf: Object (#{rdf_object}) must be a string literal" unless rdf_object =~ /^"(.+)"(@(.+))?$/
87
95
 
88
96
  lang = $3
89
97
  value = JSON.parse(%Q{["#{$1}"]})[0].gsub("\\n", "\n") # Trick to decode \uHHHHH chars
90
98
 
91
- subject.send(self.name.to_relation_name) << self.new(:target => self.label_class.new(:value => value, :language => lang))
99
+ predicate_class = Iqvoc::RDFAPI::PREDICATE_DICTIONARY[rdf_predicate] || self
100
+ predicate_class.new(:target => self.label_class.new(:value => value, :language => lang)).tap do |labeling|
101
+ rdf_subject.send(predicate_class.name.to_relation_name) << labeling
102
+ end
92
103
  end
93
104
 
94
105
  def build_rdf(document, subject)
95
- subject.send(self.rdf_namespace.camelcase).send(self.rdf_predicate, target.to_s, :lang => target.language)
106
+ subject.send(self.rdf_namespace.camelcase).send(self.rdf_predicate, target.value.to_s, :lang => target.language)
96
107
  end
97
108
 
98
109
  def build_search_result_rdf(document, result)
@@ -1,13 +1,32 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2011 innoQ Deutschland GmbH
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  class Match::SKOS::Base < Match::Base
2
18
 
3
19
  self.rdf_namespace = 'skos'
4
20
 
5
- def self.build_from_rdf(subject, predicate, object)
6
- raise "Note::SKOS::Base#build_from_rdf: Subject (#{subject}) must be able to recieve this kind of notes (#{self.name} => #{self.name.to_relation_name})." unless subject.class.reflections.include?(self.name.to_relation_name)
7
- raise "Note::SKOS::Base#build_from_rdf: Object (#{object}) must be a URI" unless object =~ /^<(.+)>$/
21
+ def self.build_from_rdf(rdf_subject, rdf_predicate, rdf_object)
22
+ raise "#{self.class}#build_from_rdf: Subject (#{rdf_subject}) must be able to recieve this kind of match (#{self.name} => #{self.name.to_relation_name})." unless rdf_subject.class.reflections.include?(self.name.to_relation_name)
23
+ raise "#{self.class}#build_from_rdf: Object (#{rdf_object}) must be a URI" unless rdf_object =~ /^<(.+)>$/ # XXX: this assumes nt-format, right?
8
24
  uri = $1
9
25
 
10
- subject.send(self.name.to_relation_name) << self.new(:value => uri)
26
+ match_class = Iqvoc::RDFAPI::PREDICATE_DICTIONARY[rdf_predicate] || self
27
+ match_class.new(:value => uri).tap do |match|
28
+ rdf_subject.send(self.name.to_relation_name) << match
29
+ end
11
30
  end
12
31
 
13
32
  def build_rdf(document, subject)
@@ -16,7 +35,7 @@ class Match::SKOS::Base < Match::Base
16
35
  if (IqRdf::Namespace.find_namespace_class(self.rdf_namespace.camelcase))
17
36
  subject.send(self.rdf_namespace.camelcase).send(self.rdf_predicate, URI.parse(value))
18
37
  else
19
- raise "Match::SKOS::MappingRelation#build_rdf: couldn't find Namespace '#{self.rdf_namespace.camelcase}'."
38
+ raise "#{self.class}#build_rdf: couldn't find Namespace '#{self.rdf_namespace.camelcase}'."
20
39
  end
21
40
  end
22
41