active-triples 0.5.0 → 0.6.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: 42a735382f3d5ad34bb75398f7dbe41bc4092ed0
4
- data.tar.gz: 64e572f52e992165f32a84202a73b6266032ce81
3
+ metadata.gz: 18f7fdc54422676d984f7e33ae9867636610e4ce
4
+ data.tar.gz: 6961ae10dc7196fd88d6cff90d353f1605bafd04
5
5
  SHA512:
6
- metadata.gz: 8e1c1c02dc97fddfb50dd818fd97087a9d8032d8e0552dc5d712da15c5f7363ed0a90eada66d2dfa28692049a6fb1ab6427ffe6167115565ca2cb66537a41d7f
7
- data.tar.gz: 4fc879ad051dd585c8eb4b1570f4b1530002e7e2b91a15ee2511b1771d38c3edf4074ee550123598e74d591173483c79141b8d174cb255ae6a385c682fcb67cd
6
+ metadata.gz: d64fbb4b48e730f62905b1dda9091ea2f43135e7c3aff5b8a2397323d2c521f79b1bb54abb52cbac4a1d786b879e1860491537b65d424dac2b001de64b79047c
7
+ data.tar.gz: 58393069ffdabc2010f82eced08a5500fe1cac7b34f73a50448065a580b241250cac5ee3acf8f0f3dd3c798b19640ac9de35b914cdd65339d4f424188e5f6712
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore CHANGED
@@ -4,3 +4,7 @@ pkg/
4
4
  Gemfile.lock
5
5
  tmp/*
6
6
  .sass-cache
7
+ .idea
8
+ coverage
9
+ .ruby-version
10
+ .ruby-gemset
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  Description
2
2
  -----------
3
3
 
4
- [![Build Status](https://travis-ci.org/no-reply/ActiveTriples.png?branch=master)](https://travis-ci.org/no-reply/ActiveTriples)
4
+ [![Build Status](https://travis-ci.org/ActiveTriples/ActiveTriples.png?branch=master)](https://travis-ci.org/ActiveTriples/ActiveTriples)
5
+ [![Coverage Status](https://coveralls.io/repos/ActiveTriples/ActiveTriples/badge.png?branch=master)](https://coveralls.io/r/ActiveTriples/ActiveTriples?branch=master)
6
+ [![Gem Version](https://badge.fury.io/rb/active-triples.svg)](http://badge.fury.io/rb/active-triples)
5
7
 
6
8
  An ActiveModel-like interface for RDF data. Models graphs as Resources with property/attribute configuration, accessors, and other methods to support Linked Data in a Ruby/Rails enviornment.
7
9
 
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'rake/clean'
2
+ require 'bundler'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_development_dependency('rdoc')
24
24
  s.add_development_dependency('rspec')
25
+ s.add_development_dependency('coveralls')
25
26
  s.add_development_dependency('guard-rspec')
26
27
  s.add_development_dependency('webmock')
27
28
  s.add_development_dependency('nokogiri')
@@ -8,7 +8,6 @@ module ActiveTriples
8
8
  autoload :Resource
9
9
  autoload :List
10
10
  autoload :Term
11
- autoload :Indexing
12
11
  autoload :Configurable
13
12
  autoload :Properties
14
13
  autoload :PropertyBuilder
@@ -19,6 +18,10 @@ module ActiveTriples
19
18
  autoload :Identifiable
20
19
  end
21
20
 
21
+ # Raised when a declared repository doesn't have a definition
22
+ class RepositoryNotFoundError < StandardError
23
+ end
24
+
22
25
  def self.class_from_string(class_name, container_class=Kernel)
23
26
  container_class = container_class.name if container_class.is_a? Module
24
27
  container_parts = container_class.split('::')
@@ -33,4 +36,22 @@ module ActiveTriples
33
36
  end
34
37
  end
35
38
  end
39
+
40
+ def self.ActiveTripels
41
+ puts <<-eos
42
+
43
+ ###########
44
+ ******o****
45
+ **o******
46
+ *******
47
+ \\***/
48
+ | |
49
+ ( )
50
+ / \\
51
+ ,---------.
52
+
53
+ eos
54
+ "Yum"
55
+ end
56
+
36
57
  end
@@ -51,13 +51,12 @@ module ActiveTriples
51
51
  attributes_collection.each do |attributes|
52
52
  attributes = attributes.with_indifferent_access
53
53
 
54
- if attributes['id'] && existing_record = association.detect { |record| record.rdf_subject.to_s == attributes['id'].to_s }
55
- if !call_reject_if(association_name, attributes)
56
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
54
+ if !call_reject_if(association_name, attributes)
55
+ if attributes['id'] && existing_record = association.detect { |record| record.rdf_subject.to_s == attributes['id'].to_s }
56
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
57
+ else
58
+ association.build(attributes.except(*UNASSIGNABLE_KEYS))
57
59
  end
58
- else
59
- attributes = attributes.with_indifferent_access
60
- association.build(attributes.except(*UNASSIGNABLE_KEYS))
61
60
  end
62
61
  end
63
62
  end
@@ -17,14 +17,15 @@ module ActiveTriples
17
17
  def self.build(model, name, options, &block)
18
18
  builder = create_builder name, options, &block
19
19
  reflection = builder.build(&block)
20
- define_accessors model, reflection
20
+ define_accessors model, reflection, options
21
21
  reflection
22
22
  end
23
23
 
24
- def self.define_accessors(model, reflection)
24
+ def self.define_accessors(model, reflection, options={})
25
25
  mixin = model.generated_property_methods
26
26
  name = reflection.term
27
27
  define_readers(mixin, name)
28
+ define_id_reader(model, name) unless options[:cast] == false
28
29
  define_writers(mixin, name)
29
30
  end
30
31
 
@@ -36,6 +37,14 @@ module ActiveTriples
36
37
  CODE
37
38
  end
38
39
 
40
+ def self.define_id_reader(mixin, name)
41
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
42
+ def #{name}_ids(*args)
43
+ get_values(:#{name}, :cast => false)
44
+ end
45
+ CODE
46
+ end
47
+
39
48
  def self.define_writers(mixin, name)
40
49
  mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
41
50
  def #{name}=(value)
@@ -7,7 +7,7 @@ module ActiveTriples
7
7
  # RDF::Repository implementation to be used for persistence of
8
8
  # resources that will be shared between ActiveFedora::Base objects.
9
9
  #
10
- # ActiveFedora::Rdf::Repositories.add_repository :blah, RDF::Repository.new
10
+ # ActiveTriples::Repositories.add_repository :blah, RDF::Repository.new
11
11
  #
12
12
  # Multiple repositories can be registered to keep different kinds of
13
13
  # resources seperate. This is configurable on subclasses of Resource
@@ -20,12 +20,12 @@ module ActiveTriples
20
20
  # end
21
21
  # end
22
22
  class Resource < RDF::Graph
23
- @@type_registry
24
23
  extend Configurable
25
24
  include Properties
26
25
  extend Deprecation
27
26
  extend ActiveModel::Naming
28
27
  extend ActiveModel::Translation
28
+ extend ActiveModel::Callbacks
29
29
  include ActiveModel::Validations
30
30
  include ActiveModel::Conversion
31
31
  include ActiveModel::Serialization
@@ -33,6 +33,7 @@ module ActiveTriples
33
33
  include NestedAttributes
34
34
  include Reflection
35
35
  attr_accessor :parent
36
+ define_model_callbacks :persist
36
37
 
37
38
  class << self
38
39
  def type_registry
@@ -227,11 +228,18 @@ module ActiveTriples
227
228
  self
228
229
  end
229
230
 
230
- def persist!
231
- raise "failed when trying to persist to non-existant repository or parent resource" unless repository
232
- erase_old_resource
233
- repository << self
234
- @persisted = true
231
+ def persist!(opts={})
232
+ return if @persisting
233
+ return false if opts[:validate] && !valid?
234
+ @persisting = true
235
+ run_callbacks :persist do
236
+ raise "failed when trying to persist to non-existant repository or parent resource" unless repository
237
+ erase_old_resource
238
+ repository << self
239
+ @persisted = true
240
+ end
241
+ @persisting = false
242
+ true
235
243
  end
236
244
 
237
245
  ##
@@ -251,9 +259,7 @@ module ActiveTriples
251
259
  # @return [true, false]
252
260
  def reload
253
261
  @term_cache ||= {}
254
- if self.class.repository == :parent
255
- return false if final_parent.nil?
256
- end
262
+ return false unless repository
257
263
  self << repository.query(subject: rdf_subject)
258
264
  unless empty?
259
265
  @persisted = true
@@ -504,7 +510,9 @@ module ActiveTriples
504
510
  if self.class.repository == :parent
505
511
  final_parent
506
512
  else
507
- Repositories.repositories[self.class.repository]
513
+ repo = Repositories.repositories[self.class.repository]
514
+ raise RepositoryNotFoundError, "The class #{self.class} expects a repository called #{self.class.repository}, but none was declared" unless repo
515
+ repo
508
516
  end
509
517
  end
510
518
 
@@ -11,6 +11,7 @@ module ActiveTriples
11
11
  def initialize(parent_resource, value_arguments)
12
12
  self.parent = parent_resource
13
13
  @reflections = parent_resource.reflections
14
+ self.term_args ||= {}
14
15
  self.value_arguments = value_arguments
15
16
  end
16
17
 
@@ -177,7 +178,8 @@ module ActiveTriples
177
178
  end
178
179
 
179
180
  def cast?
180
- return true unless property_config
181
+ return true unless property_config || (term_args && term_args[:cast])
182
+ return term_args[:cast] if term_args.has_key?(:cast)
181
183
  !!property_config[:cast]
182
184
  end
183
185
 
@@ -1,3 +1,3 @@
1
1
  module ActiveTriples
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -141,8 +141,8 @@ describe "nesting attribute behavior" do
141
141
  end
142
142
  end
143
143
 
144
- describe "with an existing object" do
145
- before(:each) do
144
+ context "a simple model" do
145
+ before do
146
146
  class SpecResource < ActiveTriples::Resource
147
147
  property :parts, predicate: RDF::DC.hasPart, :class_name=>'Component'
148
148
  accepts_nested_attributes_for :parts, allow_destroy: true
@@ -152,31 +152,57 @@ describe "nesting attribute behavior" do
152
152
  end
153
153
  end
154
154
 
155
+ SpecResource.accepts_nested_attributes_for *args
155
156
  end
157
+ after { Object.send(:remove_const, :SpecResource) }
156
158
 
157
- after(:each) do
158
- Object.send(:remove_const, :SpecResource)
159
- end
159
+ let(:args) { [:parts] }
160
160
  subject { SpecResource.new }
161
- before do
162
- subject.attributes = { parts_attributes: [
163
- {label: 'Alternator'},
164
- {label: 'Distributor'},
165
- {label: 'Transmission'},
166
- {label: 'Fuel Filter'}]}
167
- end
168
- let (:replace_object_id) { subject.parts[1].rdf_subject.to_s }
169
- let (:remove_object_id) { subject.parts[3].rdf_subject.to_s }
170
161
 
171
- it "should update nested objects" do
172
- subject.parts_attributes= [{id: replace_object_id, label: "Universal Joint"}, {label:"Oil Pump"}, {id: remove_object_id, _destroy: '1', label: "bar1 uno"}]
162
+ context "for an existing object" do
163
+ before do
164
+ subject.attributes = { parts_attributes: [
165
+ {label: 'Alternator'},
166
+ {label: 'Distributor'},
167
+ {label: 'Transmission'},
168
+ {label: 'Fuel Filter'}]}
169
+ subject.parts_attributes = new_attributes
170
+ end
171
+
172
+ context "that allows destroy" do
173
+ let(:args) { [:parts, allow_destroy: true] }
174
+ let (:replace_object_id) { subject.parts[1].rdf_subject.to_s }
175
+ let (:remove_object_id) { subject.parts[3].rdf_subject.to_s }
173
176
 
174
- expect(subject.parts.map{|p| p.label.first}).to eq ['Alternator', 'Universal Joint', 'Transmission', 'Oil Pump']
177
+ let(:new_attributes) { [{ id: replace_object_id, label: "Universal Joint" },
178
+ { label:"Oil Pump" },
179
+ { id: remove_object_id, _destroy: '1', label: "bar1 uno" }] }
175
180
 
181
+ it "should update nested objects" do
182
+ expect(subject.parts.map{|p| p.label.first}).to eq ['Alternator', 'Universal Joint', 'Transmission', 'Oil Pump']
183
+ end
184
+ end
185
+
186
+ context "when an id is provided" do
187
+ let(:new_attributes) { [{ id: 'http://example.com/part#1', label: "Universal Joint" }] }
188
+
189
+ it "creates a new statement" do
190
+ expect(subject.parts.last.rdf_subject).to eq RDF::URI('http://example.com/part#1')
191
+ end
192
+ end
176
193
  end
177
- it "create a new object when the id is provided" do
178
- subject.parts_attributes= [{id: 'http://example.com/part#1', label: "Universal Joint"}]
179
- expect(subject.parts.last.rdf_subject).to eq RDF::URI('http://example.com/part#1')
194
+
195
+ context "for a new B-node" do
196
+ context "when called with reject_if" do
197
+ let(:args) { [:parts, reject_if: reject_proc] }
198
+ let(:reject_proc) { lambda { |attributes| attributes[:label] == 'Bar' } }
199
+ let(:new_attributes) { [{ label: "Universal Joint" }, { label: 'Bar'} ] }
200
+ before { subject.parts_attributes = new_attributes }
201
+
202
+ it "should call the reject if proc" do
203
+ expect(subject.parts.map(&:label)).to eq [['Universal Joint']]
204
+ end
205
+ end
180
206
  end
181
207
  end
182
208
  end
@@ -135,13 +135,18 @@ describe ActiveTriples::Resource do
135
135
  context "and the item is not a blank node" do
136
136
 
137
137
  subject {DummyResource.new("info:fedora/example:pid")}
138
+ let(:result) { subject.persist! }
138
139
 
139
140
  before do
140
141
  @repo = RDF::Repository.new
141
142
  allow(subject.class).to receive(:repository).and_return(nil)
142
143
  allow(subject).to receive(:repository).and_return(@repo)
143
144
  subject.title = "bla"
144
- subject.persist!
145
+ result
146
+ end
147
+
148
+ it "should return true" do
149
+ expect(result).to eq true
145
150
  end
146
151
 
147
152
  it "should persist to the repository" do
@@ -158,6 +163,28 @@ describe ActiveTriples::Resource do
158
163
  expect(subject.title).to eq []
159
164
  expect(@repo.statements.to_a.length).to eq 1 # Only the type statement
160
165
  end
166
+
167
+ context "and validations are checked" do
168
+ let(:result) { subject.persist!(:validate => true) }
169
+ context "and it's valid" do
170
+ it "should return true" do
171
+ expect(result).to eq true
172
+ end
173
+ end
174
+ context "and it's invalid" do
175
+ subject do
176
+ a = DummyResource.new("info:fedora/example:pid")
177
+ allow(a).to receive(:valid?).and_return(false)
178
+ a
179
+ end
180
+ it "should return false" do
181
+ expect(result).to eq false
182
+ end
183
+ it "should not be persisted" do
184
+ expect(subject).not_to be_persisted
185
+ end
186
+ end
187
+ end
161
188
  end
162
189
  end
163
190
  end
@@ -254,6 +281,15 @@ describe ActiveTriples::Resource do
254
281
  end
255
282
  end
256
283
 
284
+ describe '#repository' do
285
+ subject { DummyLicense.new('http://example.org/cc')}
286
+
287
+ it "should warn when the repo doesn't exist" do
288
+ allow(DummyLicense).to receive(:repository).and_return('repo2')
289
+ expect { subject }.to raise_error ActiveTriples::RepositoryNotFoundError, 'The class DummyLicense expects a repository called repo2, but none was declared'
290
+ end
291
+ end
292
+
257
293
  describe '#destroy!' do
258
294
  before do
259
295
  subject.title = 'Creative Commons'
@@ -266,7 +302,7 @@ describe ActiveTriples::Resource do
266
302
  expect(subject.destroy!).to be true
267
303
  expect(subject.destroy).to be true
268
304
  end
269
-
305
+
270
306
  it 'should delete the graph' do
271
307
  subject.destroy
272
308
  expect(subject).to be_empty
@@ -400,10 +436,18 @@ describe ActiveTriples::Resource do
400
436
  it "should be empty array if we haven't set it" do
401
437
  expect(subject.aggregates).to match_array([])
402
438
  end
403
-
404
- it "should be set to a URI producing an ActiveTriple::Resource" do
405
- subject.aggregates = RDF::URI("http://example.org/b1")
406
- expect(subject.aggregates.first).to be_a ActiveTriples::Resource
439
+
440
+ context "when set to a URI" do
441
+ let(:aggregates_uri) { RDF::URI("http://example.org/b1") }
442
+ before do
443
+ subject.aggregates = aggregates_uri
444
+ end
445
+ it "produce an ActiveTriple::Resource" do
446
+ expect(subject.aggregates.first).to be_a ActiveTriples::Resource
447
+ end
448
+ it "should have an ID accessor" do
449
+ expect(subject.aggregates_ids).to eq [aggregates_uri]
450
+ end
407
451
  end
408
452
 
409
453
  it "should be settable" do
@@ -729,4 +773,24 @@ END
729
773
  expect(subject.item.first.creator.first.knows.first.foaf_name).to eq ['Bob']
730
774
  end
731
775
  end
776
+
777
+ describe "callbacks" do
778
+ describe ".before_persist" do
779
+ before do
780
+ class DummyResource < ActiveTriples::Resource
781
+ def bla
782
+ self.title = "test"
783
+ end
784
+ end
785
+ DummyResource.before_persist :bla
786
+ repository = RDF::Repository.new
787
+ allow(subject).to receive(:repository).and_return(repository)
788
+ end
789
+ it "should call prior to persisting" do
790
+ expect(subject.title).to be_blank
791
+ subject.persist!
792
+ expect(subject.title).to eq ["test"]
793
+ end
794
+ end
795
+ end
732
796
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
1
4
  require 'bundler/setup'
2
5
  Bundler.setup
3
6
 
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.5.0
4
+ version: 0.6.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-12-08 00:00:00.000000000 Z
12
+ date: 2015-01-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rdf
@@ -109,6 +109,20 @@ dependencies:
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: coveralls
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
112
126
  - !ruby/object:Gem::Dependency
113
127
  name: guard-rspec
114
128
  requirement: !ruby/object:Gem::Requirement
@@ -173,6 +187,7 @@ extra_rdoc_files:
173
187
  - LICENSE
174
188
  - README.md
175
189
  files:
190
+ - ".coveralls.yml"
176
191
  - ".gitignore"
177
192
  - ".travis.yml"
178
193
  - AUTHORS
@@ -180,12 +195,12 @@ files:
180
195
  - Guardfile
181
196
  - LICENSE
182
197
  - README.md
198
+ - Rakefile
183
199
  - active-triples.gemspec
184
200
  - lib/active/triples.rb
185
201
  - lib/active_triples.rb
186
202
  - lib/active_triples/configurable.rb
187
203
  - lib/active_triples/identifiable.rb
188
- - lib/active_triples/indexing.rb
189
204
  - lib/active_triples/list.rb
190
205
  - lib/active_triples/nested_attributes.rb
191
206
  - lib/active_triples/node_config.rb
@@ -1,76 +0,0 @@
1
- module ActiveFedora
2
- module Rdf
3
- module Indexing
4
- extend Deprecation
5
- extend ActiveSupport::Concern
6
-
7
- # In active_fedora 8, we can get the prefix part from Datastream.prefix
8
- def apply_prefix(name)
9
- "#{dsid.underscore}__#{name}"
10
- end
11
-
12
- def prefix(name)
13
- Deprecation.warn Indexing, "prefix is deprecated. Use apply_prefix instead. In active-fedora 8, the prefix method will just return the prefix to be applied, and will not do the applying. This will enable conformity between OmDatastream and RdfDatastream"
14
- apply_prefix(name)
15
- end
16
-
17
- def to_solr(solr_doc = Hash.new) # :nodoc:
18
- fields.each do |field_key, field_info|
19
- values = resource.get_values(field_key)
20
- Array(values).each do |val|
21
- if val.kind_of? RDF::URI
22
- val = val.to_s
23
- elsif val.kind_of? Rdf::Resource
24
- val = val.solrize
25
- end
26
- self.class.create_and_insert_terms(apply_prefix(field_key), val, field_info[:behaviors], solr_doc)
27
- end
28
- end
29
- solr_doc
30
- end
31
-
32
- # Gives the primary solr name for a column. If there is more than one indexer on the field definition, it gives the first
33
- def primary_solr_name(field)
34
- config = self.class.config_for_term_or_uri(field)
35
- return nil unless config # punt on index names for deep nodes!
36
- if behaviors = config.behaviors
37
- behaviors.each do |behavior|
38
- result = ActiveFedora::SolrService.solr_name(apply_prefix(field), behavior, type: config.type)
39
- return result if Solrizer::DefaultDescriptors.send(behavior).evaluate_suffix(:text).stored?
40
- end
41
- raise RuntimeError "no stored fields were found"
42
- end
43
- end
44
-
45
- module ClassMethods
46
- def prefix(dsid, name)
47
- Deprecation.warn Indexing, "prefix is deprecated and will be removed in active-fedora 8.0.0.", caller
48
- "#{dsid.underscore}__#{name}".to_sym
49
- end
50
-
51
- # Gives the datatype for a column.
52
- def type(field)
53
- config_for_term_or_uri(field).type
54
- end
55
- end
56
-
57
- private
58
- # returns a Hash, e.g.: {field => {:values => [], :type => :something, :behaviors => []}, ...}
59
- def fields
60
- field_map = {}.with_indifferent_access
61
-
62
- self.class.properties.each do |name, config|
63
- type = config[:type]
64
- behaviors = config[:behaviors]
65
- next unless type and behaviors
66
- next if config[:class_name] && config[:class_name] < ActiveFedora::Base
67
- resource.query(:subject => rdf_subject, :predicate => config[:predicate]).each_statement do |statement|
68
- field_map[name] ||= {:values => [], :type => type, :behaviors => behaviors}
69
- field_map[name][:values] << statement.object.to_s
70
- end
71
- end
72
- field_map
73
- end
74
- end
75
- end
76
- end