active-triples 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a31ce4cccede2e3befa05a4b20dc4894547b219a
4
- data.tar.gz: 8c47c1b2ad7a9514298dbae6f290c09313590c6d
3
+ metadata.gz: 6fe9b5e7c31b1ebd51f2c529d354c27ff5a50461
4
+ data.tar.gz: 96039e8d7e41040748705955d064101fce40f236
5
5
  SHA512:
6
- metadata.gz: dea13110704ca324e2cce448cd413450e21c0a6837ea269f7be8aa783b5540f85d9a11df04a2a891c1986ed40eb551347b06119547518c7e43c093cc715504c8
7
- data.tar.gz: 82fbe1c1025d727d396eb8e3c612b56b209d40bac4bec074cef008afa91c052a58e7b344a38a47b29943d725f273776c83b04070a403abcf53adbdf3a6682372
6
+ metadata.gz: 6c2474afde1a6b48790bed08a67caf0e413f8339cfa5993f0ef6bcb277cf642c21bc5d0f2e1ce830f735766d704ca35cd6bacc3076a1645d52f96f28ba44cd7a
7
+ data.tar.gz: abbe7fd8978112727f975413aa4cb5bb9a20cfc443c4e2f128d4469010391f20bc79e3466575e68153413b1db7763c7be1aa7f633ed6c75796e3213ac460af37
@@ -1,16 +1,22 @@
1
1
  require 'rdf'
2
2
  require 'active_triples/version'
3
+ require 'active_support'
3
4
 
4
5
  module ActiveTriples
5
- autoload :Resource, 'active_triples/resource'
6
- autoload :List, 'active_triples/list'
7
- autoload :Term, 'active_triples/term'
8
- autoload :Indexing, 'active_triples/indexing'
9
- autoload :Configurable, 'active_triples/configurable'
10
- autoload :Properties, 'active_triples/properties'
11
- autoload :Repositories, 'active_triples/repositories'
12
- autoload :NodeConfig, 'active_triples/node_config'
13
- autoload :NestedAttributes, 'active_triples/nested_attributes'
6
+ extend ActiveSupport::Autoload
7
+ eager_autoload do
8
+ autoload :Resource
9
+ autoload :List
10
+ autoload :Term
11
+ autoload :Indexing
12
+ autoload :Configurable
13
+ autoload :Properties
14
+ autoload :PropertyBuilder
15
+ autoload :Reflection
16
+ autoload :Repositories
17
+ autoload :NodeConfig
18
+ autoload :NestedAttributes
19
+ end
14
20
 
15
21
  def self.class_from_string(class_name, container_class=Kernel)
16
22
  container_class = container_class.name if container_class.is_a? Module
@@ -8,7 +8,8 @@ module ActiveTriples
8
8
  class List < RDF::List
9
9
  include ActiveTriples::NestedAttributes
10
10
  extend Configurable
11
- extend Properties
11
+ include Properties
12
+ include Reflection
12
13
 
13
14
  delegate :rdf_subject, :mark_for_destruction, :marked_for_destruction?, :set_value, :get_values, :parent, :type, :dump, :attributes=, to: :resource
14
15
  alias_method :to_ary, :to_a
@@ -30,10 +31,6 @@ module ActiveTriples
30
31
  @graph = ListResource.new(subject) << graph unless graph.kind_of? Resource
31
32
  graph << parent if parent
32
33
  graph.list = self
33
- graph.singleton_class.properties = self.class.properties
34
- graph.singleton_class.properties.keys.each do |property|
35
- graph.singleton_class.send(:register_property, property)
36
- end
37
34
  graph.reload
38
35
  end
39
36
 
@@ -107,11 +104,15 @@ module ActiveTriples
107
104
  @list ||= list
108
105
  end
109
106
 
107
+ def reflections
108
+ @list.class
109
+ end
110
+
110
111
  def attributes=(values)
111
112
  raise ArgumentError, "values must be a Hash, you provided #{values.class}" unless values.kind_of? Hash
112
113
  values.with_indifferent_access.each do |key, value|
113
- if self.singleton_class.properties.keys.map{ |k| "#{k}_attributes"}.include?(key)
114
- klass = properties[key[0..-12]]['class_name']
114
+ if reflections.properties.keys.map { |k| "#{k}_attributes" }.include?(key)
115
+ klass = reflections.reflect_on_property(key[0..-12])['class_name']
115
116
  klass = ActiveTriples.class_from_string(klass, final_parent.class) if klass.is_a? String
116
117
  value.is_a?(Hash) ? attributes_hash_to_list(values[key], klass) : attributes_to_list(value, klass)
117
118
  values.delete key
@@ -159,9 +160,9 @@ module ActiveTriples
159
160
  when Array then RDF::List.new(nil, graph, value)
160
161
  else value
161
162
  end
162
-
163
+
163
164
  if subject == RDF.nil
164
- @subject = RDF::Node.new
165
+ @subject = RDF::Node.new
165
166
  @graph = ListResource.new(subject)
166
167
  @graph.type = RDF.List
167
168
  end
@@ -50,7 +50,7 @@ module ActiveTriples
50
50
 
51
51
  attributes_collection.each do |attributes|
52
52
  attributes = attributes.with_indifferent_access
53
-
53
+
54
54
  if attributes['id'] && existing_record = association.detect { |record| record.rdf_subject.to_s == attributes['id'].to_s }
55
55
  if !call_reject_if(association_name, attributes)
56
56
  assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
@@ -83,7 +83,7 @@ module ActiveTriples
83
83
  def has_destroy_flag?(hash)
84
84
  ["1", "true"].include?(hash['_destroy'].to_s)
85
85
  end
86
-
86
+
87
87
  module ClassMethods
88
88
  def accepts_nested_attributes_for *attr_names
89
89
  options = { :allow_destroy => false, :update_only => false }
@@ -6,8 +6,9 @@ module ActiveTriples
6
6
  self.term = term
7
7
  self.predicate = predicate
8
8
  self.class_name = args.delete(:class_name)
9
- self.multivalue = args.delete(:multivalue) { true }
9
+ self.multivalue = args.delete(:multivalue) { true }
10
10
  raise ArgumentError, "Invalid arguments for Rdf Node configuration: #{args} on #{predicate}" unless args.empty?
11
+ yield(self) if block_given?
11
12
  end
12
13
 
13
14
  def [](value)
@@ -11,73 +11,59 @@ module ActiveTriples
11
11
  # property :title, predicate: RDF::DC.title, class_name: ResourceClass
12
12
  #
13
13
  module Properties
14
- attr_accessor :config
14
+ extend ActiveSupport::Concern
15
15
 
16
- ##
17
- # Registers properties for Resource-like classes
18
- # @param [Symbol] name of the property (and its accessor methods)
19
- # @param [Hash] opts for this property, must include a :predicate
20
- # @yield [index] index sets solr behaviors for the property
21
- def property(name, opts={}, &block)
22
- self.config[name] = NodeConfig.new(name, opts[:predicate], opts.except(:predicate)).tap do |config|
23
- config.with_index(&block) if block_given?
24
- end
25
- behaviors = config[name].behaviors.flatten if config[name].behaviors and not config[name].behaviors.empty?
26
- register_property(name)
16
+ included do
17
+ initialize_generated_modules
27
18
  end
28
19
 
29
- ##
30
- # Returns the properties registered to the class and their
31
- # configurations.
32
- #
33
- # @return [ActiveSupport::HashWithIndifferentAccess{String => ActiveTriples::NodeConfig}]
34
- def config
35
- @config ||= if superclass.respond_to? :config
36
- superclass.config.dup
37
- else
38
- {}.with_indifferent_access
20
+ module ClassMethods
21
+ def inherited(child_class) #:nodoc:
22
+ child_class.initialize_generated_modules
23
+ super
39
24
  end
40
- end
41
-
42
- alias_method :properties, :config
43
- alias_method :properties=, :config=
44
25
 
45
- ##
46
- # Given a property name or a predicate, return the configuration
47
- # for the matching property.
48
- #
49
- # @param term [#to_sym, RDF::Resource] a property name to predicate
50
- #
51
- # @return [ActiveTriples::NodeConfig]
52
- def config_for_term_or_uri(term)
53
- return config[term.to_sym] unless term.kind_of? RDF::Resource
54
- config.each { |k, v| return v if v.predicate == term.to_uri }
55
- end
26
+ def initialize_generated_modules # :nodoc:
27
+ generated_property_methods
28
+ end
56
29
 
57
- ##
58
- # List the property names registered to the class.
59
- #
60
- # @return [Array<Symbol>] list of the symbolized names of registered
61
- # properties
62
- def fields
63
- properties.keys.map(&:to_sym)
64
- end
30
+ def generated_property_methods
31
+ @generated_property_methods ||= begin
32
+ mod = const_set(:GeneratedPropertyMethods, Module.new)
33
+ include mod
34
+ mod
35
+ end
36
+ end
65
37
 
66
- private
38
+ ##
39
+ # Registers properties for Resource-like classes
40
+ # @param [Symbol] name of the property (and its accessor methods)
41
+ # @param [Hash] opts for this property, must include a :predicate
42
+ # @yield [index] index sets solr behaviors for the property
43
+ def property(name, opts={}, &block)
44
+ reflection = PropertyBuilder.build(self, name, opts, &block)
45
+ Reflection.add_reflection self, name, reflection
46
+ end
67
47
 
68
- ##
69
- # Private method for creating accessors for a given property.
70
- #
71
- # @param [#to_s] name Name of the accessor to be created,
72
- # get/set_value is called on the resource using this.
73
- def register_property(name)
74
- parent = Proc.new{self}
75
- # parent = Proc.new{resource} if self < ActiveFedora::Datastream
76
- define_method "#{name}=" do |*args|
77
- instance_eval(&parent).set_value(name.to_sym, *args)
48
+ ##
49
+ # Given a property name or a predicate, return the configuration
50
+ # for the matching property.
51
+ #
52
+ # @param term [#to_sym, RDF::Resource] a property name to predicate
53
+ #
54
+ # @return [ActiveTriples::NodeConfig]
55
+ def config_for_term_or_uri(term)
56
+ return config[term.to_sym] unless term.kind_of? RDF::Resource
57
+ config.each_value { |v| return v if v.predicate == term.to_uri }
78
58
  end
79
- define_method name do
80
- instance_eval(&parent).get_values(name.to_sym)
59
+
60
+ ##
61
+ # List the property names registered to the class.
62
+ #
63
+ # @return [Array<Symbol>] list of the symbolized names of registered
64
+ # properties
65
+ def fields
66
+ properties.keys.map(&:to_sym)
81
67
  end
82
68
  end
83
69
  end
@@ -0,0 +1,53 @@
1
+ module ActiveTriples
2
+ class PropertyBuilder
3
+
4
+ attr_reader :name, :options
5
+
6
+ def initialize(name, options, &block)
7
+ @name = name
8
+ @options = options
9
+ end
10
+
11
+ def self.create_builder(name, options, &block)
12
+ raise ArgumentError, "property names must be a Symbol" unless name.kind_of?(Symbol)
13
+
14
+ new(name, options, &block)
15
+ end
16
+
17
+ def self.build(model, name, options, &block)
18
+ builder = create_builder name, options, &block
19
+ reflection = builder.build(&block)
20
+ define_accessors model, reflection
21
+ reflection
22
+ end
23
+
24
+ def self.define_accessors(model, reflection)
25
+ mixin = model.generated_property_methods
26
+ name = reflection.term
27
+ define_readers(mixin, name)
28
+ define_writers(mixin, name)
29
+ end
30
+
31
+ def self.define_readers(mixin, name)
32
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
33
+ def #{name}(*args)
34
+ get_values(:#{name})
35
+ end
36
+ CODE
37
+ end
38
+
39
+ def self.define_writers(mixin, name)
40
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
41
+ def #{name}=(value)
42
+ set_value(:#{name}, value)
43
+ end
44
+ CODE
45
+ end
46
+
47
+ def build(&block)
48
+ NodeConfig.new(name, options[:predicate], options.except(:predicate)) do |config|
49
+ config.with_index(&block) if block_given?
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/core_ext/class'
2
+
3
+ module ActiveTriples
4
+ module Reflection
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ class_attribute :_active_triples_config
9
+ self._active_triples_config = {}
10
+ end
11
+
12
+ def self.add_reflection(model, name, reflection)
13
+ model._active_triples_config = model._active_triples_config.merge(name.to_s => reflection)
14
+ end
15
+
16
+ module ClassMethods
17
+ def reflect_on_property(term)
18
+ _active_triples_config[term.to_s]
19
+ end
20
+
21
+ def properties
22
+ _active_triples_config
23
+ end
24
+
25
+ def properties=(val)
26
+ self._active_triples_config = val
27
+ end
28
+ end
29
+ end
30
+ end
@@ -22,7 +22,7 @@ module ActiveTriples
22
22
  class Resource < RDF::Graph
23
23
  @@type_registry
24
24
  extend Configurable
25
- extend Properties
25
+ include Properties
26
26
  extend Deprecation
27
27
  extend ActiveModel::Naming
28
28
  extend ActiveModel::Translation
@@ -31,6 +31,7 @@ module ActiveTriples
31
31
  include ActiveModel::Serialization
32
32
  include ActiveModel::Serializers::JSON
33
33
  include NestedAttributes
34
+ include Reflection
34
35
  attr_accessor :parent
35
36
 
36
37
  class << self
@@ -116,14 +117,18 @@ module ActiveTriples
116
117
  hash
117
118
  end
118
119
 
120
+ def reflections
121
+ self.class
122
+ end
123
+
119
124
  def attributes=(values)
120
125
  raise ArgumentError, "values must be a Hash, you provided #{values.class}" unless values.kind_of? Hash
121
126
  values = values.with_indifferent_access
122
127
  set_subject!(values.delete(:id)) if values.has_key?(:id) and node?
123
128
  values.each do |key, value|
124
- if properties.keys.include?(key)
129
+ if reflections.reflect_on_property(key)
125
130
  set_value(rdf_subject, key, value)
126
- elsif self.singleton_class.nested_attributes_options.keys.map{ |k| "#{k}_attributes"}.include?(key)
131
+ elsif nested_attributes_options.keys.map { |k| "#{k}_attributes" }.include?(key)
127
132
  send("#{key}=".to_sym, value)
128
133
  else
129
134
  raise ArgumentError, "No association found for name `#{key}'. Has it been defined yet?"
@@ -143,7 +148,7 @@ module ActiveTriples
143
148
  # @return [String]
144
149
  def dump(*args)
145
150
  if args.first == :jsonld and respond_to?(:jsonld_context)
146
- args << {} unless args.last.is_a?(Hash)
151
+ args << {} unless args.last.is_a?(Hash)
147
152
  args.last[:context] ||= jsonld_context
148
153
  end
149
154
  super
@@ -206,16 +211,16 @@ module ActiveTriples
206
211
  end
207
212
 
208
213
  ##
209
- # Load data from the #rdf_subject URI. Retrieved data will be
214
+ # Load data from the #rdf_subject URI. Retrieved data will be
210
215
  # parsed into the Resource's graph from available RDF::Readers
211
- # and available from property accessors if if predicates are
216
+ # and available from property accessors if if predicates are
212
217
  # registered.
213
- #
218
+ #
214
219
  # osu = ActiveTriples::Resource.new('http://dbpedia.org/resource/Oregon_State_University')
215
220
  # osu.fetch
216
221
  # osu.rdf_label.first
217
222
  # # => "Oregon State University"
218
- #
223
+ #
219
224
  # @return [ActiveTriples::Resource] self
220
225
  def fetch
221
226
  load(rdf_subject)
@@ -405,23 +410,23 @@ module ActiveTriples
405
410
  end
406
411
 
407
412
  private
408
-
413
+
409
414
  ##
410
415
  # Returns the properties registered and their configurations.
411
416
  #
412
417
  # @return [ActiveSupport::HashWithIndifferentAccess{String => ActiveTriples::NodeConfig}]
413
418
  def properties
414
- self.singleton_class.properties
419
+ _active_triples_config
415
420
  end
416
421
 
417
422
  ##
418
423
  # List of RDF predicates registered as properties on the object.
419
424
  #
420
425
  # @return [Array<RDF::URI>]
421
- def registered_predicates
426
+ def registered_predicates
422
427
  properties.values.map { |config| config.predicate }
423
428
  end
424
-
429
+
425
430
  ##
426
431
  # List of RDF predicates used in the Resource's triples, but not
427
432
  # mapped to any property or accessor methods.
@@ -434,12 +439,12 @@ module ActiveTriples
434
439
  end
435
440
 
436
441
  ##
437
- # Given a predicate which has been registered to a property,
442
+ # Given a predicate which has been registered to a property,
438
443
  # returns the name of the matching property.
439
444
  #
440
445
  # @param predicate [RDF::URI]
441
446
  #
442
- # @return [String, nil] the name of the property mapped to the
447
+ # @return [String, nil] the name of the property mapped to the
443
448
  # predicate provided
444
449
  def property_for_predicate(predicate)
445
450
  properties.each do |property, values|
@@ -463,7 +468,7 @@ module ActiveTriples
463
468
  # @return [RDF::Repository, ActiveTriples::Resource] the target
464
469
  # repository
465
470
  def repository
466
- @repository ||=
471
+ @repository ||=
467
472
  if self.class.repository == :parent
468
473
  final_parent
469
474
  else
@@ -476,16 +481,16 @@ module ActiveTriples
476
481
  # an RDF term. If a String is given, first tries to interpret it
477
482
  # as a valid URI, then tries to append it to base_uri. Finally,
478
483
  # raises an error if no valid term can be built.
479
- #
484
+ #
480
485
  # The argument must be an RDF::Node, an object that responds to
481
486
  # #to_uri, a String that represents a valid URI, or a String that
482
487
  # appends to the Resource's base_uri to create a valid URI.
483
488
  #
484
- # @TODO: URI.scheme_list is naive and incomplete. Find a better
489
+ # @TODO: URI.scheme_list is naive and incomplete. Find a better
485
490
  # way to check for an existing scheme.
486
491
  #
487
492
  # @param uri_or_str [RDF::Resource, String]
488
- #
493
+ #
489
494
  # @return [RDF::Resource] A term
490
495
  # @raise [RuntimeError] no valid RDF term could be built
491
496
  def get_uri(uri_or_str)
@@ -4,11 +4,13 @@ module ActiveTriples
4
4
  class Term
5
5
 
6
6
  attr_accessor :parent, :value_arguments, :node_cache
7
+ attr_reader :reflections
7
8
 
8
9
  delegate *(Array.public_instance_methods - [:send, :__send__, :__id__, :class, :object_id] + [:as_json]), :to => :result
9
10
 
10
- def initialize(parent, value_arguments)
11
- self.parent = parent
11
+ def initialize(parent_resource, value_arguments)
12
+ self.parent = parent_resource
13
+ @reflections = parent_resource.reflections
12
14
  self.value_arguments = value_arguments
13
15
  end
14
16
 
@@ -18,8 +20,10 @@ module ActiveTriples
18
20
 
19
21
  def result
20
22
  result = parent.query(:subject => rdf_subject, :predicate => predicate)
21
- .map{|x| convert_object(x.object)}
22
- .reject(&:nil?)
23
+ .each_with_object([]) do |x, collector|
24
+ converted_object = convert_object(x.object)
25
+ collector << converted_object unless converted_object.nil?
26
+ end
23
27
  return result if !property_config || property_config[:multivalue]
24
28
  result.first
25
29
  end
@@ -42,9 +46,9 @@ module ActiveTriples
42
46
  end
43
47
 
44
48
  def build(attributes={})
45
- new_subject = attributes.key?('id') ? attributes.delete('id') : RDF::Node.new
49
+ new_subject = attributes.fetch('id') { RDF::Node.new }
46
50
  make_node(new_subject).tap do |node|
47
- node.attributes = attributes
51
+ node.attributes = attributes.except('id')
48
52
  if parent.kind_of? List::ListResource
49
53
  parent.list << node
50
54
  elsif node.kind_of? RDF::List
@@ -73,8 +77,8 @@ module ActiveTriples
73
77
  alias_method :push, :<<
74
78
 
75
79
  def property_config
76
- return type_property if (property == RDF.type || property.to_s == "type") && !parent.send(:properties)[property]
77
- parent.send(:properties)[property]
80
+ return type_property if (property == RDF.type || property.to_s == "type") && (!reflections.kind_of?(Resource) || !reflections.reflect_on_property(property))
81
+ reflections.reflect_on_property(property)
78
82
  end
79
83
 
80
84
  def type_property
@@ -113,7 +117,7 @@ module ActiveTriples
113
117
  return
114
118
  end
115
119
  val = val.to_uri if val.respond_to? :to_uri
116
- raise 'value must be an RDF URI, Node, Literal, or a valid datatype. See RDF::Literal' unless
120
+ raise "value must be an RDF URI, Node, Literal, or a valid datatype. See RDF::Literal.\n\tYou provided #{val.inspect}" unless
117
121
  val.kind_of? RDF::Value or val.kind_of? RDF::Literal
118
122
  parent.insert [rdf_subject, predicate, val]
119
123
  end
@@ -144,7 +148,7 @@ module ActiveTriples
144
148
  def convert_object(value)
145
149
  case value
146
150
  when RDF::Literal
147
- value.object
151
+ value.object
148
152
  when RDF::Resource
149
153
  make_node(value)
150
154
  else
@@ -1,3 +1,3 @@
1
1
  module ActiveTriples
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -29,7 +29,8 @@ describe ActiveTriples::Configurable do
29
29
 
30
30
  describe '#rdf_type' do
31
31
  it "should set the type the old way" do
32
- DummyConfigurable.should_receive(:configure).with(type: RDF::RDFS.Class).and_call_original
32
+ expect(DummyConfigurable).to receive(:configure).with(type: RDF::RDFS.Class).and_call_original
33
+ expect(Deprecation).to receive(:warn)
33
34
  DummyConfigurable.rdf_type(RDF::RDFS.Class)
34
35
  expect(DummyConfigurable.type).to eq RDF::RDFS.Class
35
36
  end
@@ -5,7 +5,7 @@ require 'linkeddata'
5
5
  describe ActiveTriples::List do
6
6
 
7
7
  subject { ActiveTriples::List.new }
8
-
8
+
9
9
  context 'when empty' do
10
10
  it 'has subject of RDF.nil' do
11
11
  expect(subject.subject).to eq RDF.nil
@@ -43,7 +43,7 @@ describe ActiveTriples::List do
43
43
  it 'has correct number of elements' do
44
44
  expect(subject.length).to eq 3
45
45
  end
46
-
46
+
47
47
  context 'after clear' do
48
48
  before do
49
49
  subject.clear
@@ -247,7 +247,7 @@ END
247
247
  expect(doc.xpath('//mads:ComplexSubject/mads:elementList/*[position() = 2]/mads:elementValue', ns).map(&:text)).to eq ["Relations with Mexican Americans"]
248
248
  expect(doc.xpath('//mads:ComplexSubject/mads:elementList/*[position() = 3]/@rdf:about', ns).map(&:value)).to eq ["http://library.ucsd.edu/ark:/20775/bbXXXXXXX4"]
249
249
  expect(doc.xpath('//mads:ComplexSubject/mads:elementList/*[position() = 4]/mads:elementValue', ns).map(&:text)).to eq ["1900s"]
250
- expect(RDF::List.new(list.rdf_subject, subject.graph)).to be_valid
250
+ expect(RDF::List.new(list.rdf_subject, subject)).to be_valid
251
251
  end
252
252
 
253
253
  it "should be a valid list" do
@@ -255,9 +255,9 @@ END
255
255
  # TODO this is a workaround for https://github.com/projecthydra/active_fedora/issues/444
256
256
  # remove the following line when #444 is closed.
257
257
  list.resource.persist!
258
- expect(RDF::List.new(list.rdf_subject, subject.graph)).to be_valid
258
+ expect(RDF::List.new(list.rdf_subject, subject)).to be_valid
259
259
  end
260
- end
260
+ end
261
261
  end
262
262
  end
263
263
  end
@@ -85,7 +85,7 @@ describe "nesting attribute behavior" do
85
85
  personalName_attributes: [
86
86
  {
87
87
  id: 'http://library.ucsd.edu/ark:20775/jefferson',
88
- elementList_attributes: [{
88
+ elementList_attributes: [{
89
89
  fullNameElement: "Jefferson, Thomas",
90
90
  dateNameElement: "1743-1826"
91
91
  }]
@@ -123,12 +123,12 @@ describe "nesting attribute behavior" do
123
123
  expect(subject.personalName.first.elementList.first.fullNameElement).to eq ["Jefferson, Thomas"]
124
124
  expect(subject.personalName.first.elementList.first.dateNameElement).to eq ["1743-1826"]
125
125
  end
126
-
126
+
127
127
  it 'should build nodes with ids' do
128
128
  expect(subject.topic[0].elementList.first[0].rdf_subject).to eq 'http://library.ucsd.edu/ark:/20775/bb3333333x'
129
129
  expect(subject.personalName.first.rdf_subject).to eq 'http://library.ucsd.edu/ark:20775/jefferson'
130
130
  end
131
-
131
+
132
132
  it 'should fail when writing to a non-predicate' do
133
133
  attributes = { topic_attributes: { '0' => { elementList_attributes: [{ topicElement_attributes: [{ fake_predicate:"Cosmology" }] }]}}}
134
134
  expect{ subject.attributes = attributes }.to raise_error ArgumentError
@@ -2,7 +2,8 @@ require "spec_helper"
2
2
  describe ActiveTriples::Properties do
3
3
  before do
4
4
  class DummyProperties
5
- extend ActiveTriples::Properties
5
+ include ActiveTriples::Reflection
6
+ include ActiveTriples::Properties
6
7
  end
7
8
  end
8
9
 
@@ -13,29 +14,29 @@ describe ActiveTriples::Properties do
13
14
  describe '#property' do
14
15
  it 'should set a property' do
15
16
  DummyProperties.property :title, :predicate => RDF::DC.title
16
- expect(DummyProperties.properties).to include :title
17
+ expect(DummyProperties.reflect_on_property(:title)).to be_kind_of ActiveTriples::NodeConfig
17
18
  end
18
19
 
19
20
  it 'should set index behaviors' do
20
21
  DummyProperties.property :title, :predicate => RDF::DC.title do |index|
21
22
  index.as :facetable, :searchable
22
23
  end
23
- expect(DummyProperties.properties[:title][:behaviors]).to eq [:facetable, :searchable]
24
+ expect(DummyProperties.reflect_on_property(:title)[:behaviors]).to eq [:facetable, :searchable]
24
25
  end
25
26
 
26
27
  it 'should set class name' do
27
28
  DummyProperties.property :title, :predicate => RDF::DC.title, :class_name => RDF::Literal
28
- expect(DummyProperties.properties[:title][:class_name]).to eq RDF::Literal
29
+ expect(DummyProperties.reflect_on_property(:title)[:class_name]).to eq RDF::Literal
29
30
  end
30
31
 
31
32
  it "should constantize string class names" do
32
33
  DummyProperties.property :title, :predicate => RDF::DC.title, :class_name => "RDF::Literal"
33
- expect(DummyProperties.properties[:title][:class_name]).to eq RDF::Literal
34
+ expect(DummyProperties.reflect_on_property(:title)[:class_name]).to eq RDF::Literal
34
35
  end
35
36
 
36
37
  it "should keep strings which it can't constantize as strings" do
37
38
  DummyProperties.property :title, :predicate => RDF::DC.title, :class_name => "FakeClassName"
38
- expect(DummyProperties.properties[:title][:class_name]).to eq "FakeClassName"
39
+ expect(DummyProperties.reflect_on_property(:title)[:class_name]).to eq "FakeClassName"
39
40
  end
40
41
  end
41
42
 
@@ -52,7 +53,8 @@ describe ActiveTriples::Properties do
52
53
  end
53
54
 
54
55
  it 'should carry properties from superclass' do
55
- expect(DummySubClass.properties.keys).to eq ["title", "source"]
56
+ expect(DummySubClass.reflect_on_property(:title)).to be_kind_of ActiveTriples::NodeConfig
57
+ expect(DummySubClass.reflect_on_property(:source)).to be_kind_of ActiveTriples::NodeConfig
56
58
  end
57
59
  end
58
60
  end
@@ -202,7 +202,7 @@ describe ActiveTriples::Resource do
202
202
  end
203
203
  end
204
204
  end
205
-
205
+
206
206
  describe 'class_name' do
207
207
  it 'should raise an error when not a class or string' do
208
208
  DummyResource.property :relation, :predicate => RDF::DC.relation, :class_name => RDF::URI('http://example.org')
@@ -210,14 +210,33 @@ describe ActiveTriples::Resource do
210
210
  d.relation = RDF::DC.type
211
211
  expect { d.relation.first }.to raise_error "class_name for relation is a RDF::URI; must be a class"
212
212
  end
213
-
213
+
214
214
  it 'should return nil when none is given' do
215
- expect(DummyResource.properties['title'][:class_name]).to be_nil
215
+ expect(DummyResource.reflect_on_property('title')[:class_name]).to be_nil
216
216
  end
217
+
217
218
  end
218
-
219
+
220
+ context 'property configuration' do
221
+ it 'preserves previous #properties[] API but prefers #reflect_on_property' do
222
+ expect(DummyResource.reflect_on_property('title')).to eq(DummyResource.properties.fetch('title'))
223
+ end
224
+
225
+ it 'uses hash access on #properties to retrieve the configuration' do
226
+ expect(DummyResource.properties['title']).to be_a(ActiveTriples::NodeConfig)
227
+ end
228
+
229
+ it 'stores the properties configuration as a hash' do
230
+ expect(DummyResource.properties).to be_a(Hash)
231
+ end
232
+
233
+ it "uses reflection to retrieve a property's configuration" do
234
+ expect(DummyResource.reflect_on_property('title')).to be_a(ActiveTriples::NodeConfig)
235
+ end
236
+ end
237
+
219
238
  describe 'attributes' do
220
- before do
239
+ before do
221
240
  subject.license = license
222
241
  subject.title = 'moomi'
223
242
  end
@@ -4,7 +4,10 @@ require 'rdf/isomorphic'
4
4
  describe ActiveTriples::Term do
5
5
 
6
6
  describe "#rdf_subject" do
7
- subject { described_class.new( double("parent"), double("value args") ) }
7
+ let(:parent_resource) { double("parent resource", reflections: {}) }
8
+
9
+ subject { described_class.new(parent_resource, double("value args") ) }
10
+
8
11
  context "when term has 0 value arguments" do
9
12
  before { subject.value_arguments = double(length: 0) }
10
13
  it "should raise an error" do
@@ -35,7 +38,7 @@ describe ActiveTriples::Term do
35
38
  end
36
39
 
37
40
  describe "#valid_datatype?" do
38
- subject { described_class.new( double("parent"), "value" ) }
41
+ subject { described_class.new(double("parent", reflections: []), "value" ) }
39
42
  before { allow(subject.parent).to receive(:rdf_subject) { "parent subject" } }
40
43
  context "the value is not a Resource" do
41
44
  it "should be true if value is a String" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active-triples
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Johnson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-08-22 00:00:00.000000000 Z
12
+ date: 2014-10-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rdf
@@ -189,6 +189,8 @@ files:
189
189
  - lib/active_triples/nested_attributes.rb
190
190
  - lib/active_triples/node_config.rb
191
191
  - lib/active_triples/properties.rb
192
+ - lib/active_triples/property_builder.rb
193
+ - lib/active_triples/reflection.rb
192
194
  - lib/active_triples/repositories.rb
193
195
  - lib/active_triples/resource.rb
194
196
  - lib/active_triples/term.rb