tripod 0.9.7 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d0d0bb81441871fbdb4115e399bca413f309c7c4
4
- data.tar.gz: 3b72bae40446b70dd252383f82193c4764a2b669
3
+ metadata.gz: 9c4f4a91c3753acb50660407e1862de999314cf6
4
+ data.tar.gz: 097ab255b4abf50836e5e13844dd96ccfd74e036
5
5
  SHA512:
6
- metadata.gz: 614d0632c00fd4b5c99347f035fad525a2e9a9cf9240cd9376bf1c6fa1585ccda99a28ff0c8f74c988f7c8480723845195b6ffc74d05b5a7c1321ba849436062
7
- data.tar.gz: 515dafcdb449015ef2b8728b00c65687f3d777e232022e34e9d96311a77229a7c9b2eea7332ea6dae7c19c34ba34a52e2b6117bc038fa81314cbba64b819b795
6
+ metadata.gz: cd7b93b8990be65d54c964f347420d74c2c1d2327d9356e4d32e6d831cd751fb96916788e27be8b212d25400f2e7fe0f1ee68857ff28e0601473bd89805a20ec
7
+ data.tar.gz: bda4ed335ee7b00600ffaf219805b7f725a4f59d292a7f7a9ce428df017e8bacbf554dfdc8da8a63a2e281e5aad510ecb8eba1fdface9587682887c5526863b7
@@ -19,6 +19,7 @@ module Tripod::Components
19
19
  include Tripod::Validations
20
20
  include Tripod::Persistence
21
21
  include Tripod::Fields
22
+ include Tripod::Links
22
23
  include Tripod::Finders
23
24
  include Tripod::Repository
24
25
  include Tripod::EagerLoading
@@ -6,6 +6,7 @@ module Tripod::Fields
6
6
  # Set readers for the instance variables.
7
7
  attr_accessor :name, :predicate, :options, :datatype, :is_uri, :multivalued
8
8
  alias_method :is_uri?, :is_uri
9
+ alias_method :multivalued?, :multivalued
9
10
 
10
11
  # Create the new field with a name and optional additional options.
11
12
  #
data/lib/tripod/fields.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require "tripod/fields/standard"
3
3
 
4
- # This module defines behaviour for fields.
4
+ # This module defines behaviour for fields.
5
5
  module Tripod::Fields
6
6
  extend ActiveSupport::Concern
7
7
 
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ module Tripod::Links
3
+ # Defines the behaviour for defined links in the resource.
4
+ class LinkedFrom
5
+
6
+ # Set readers for the instance variables.
7
+ attr_accessor :name, :incoming_field, :options, :incoming_field_name, :class_name
8
+
9
+ # Create the new link with a name and optional additional options.
10
+ def initialize(name, incoming_field_name, options = {})
11
+ @name = name
12
+ @options = options
13
+ @incoming_field_name = incoming_field_name
14
+ # if class name not supplied, guess from the field name
15
+ @class_name = options[:class_name] || name.to_s.singularize.classify
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ module Tripod::Links
3
+ # Defines the behaviour for defined links in the resource.
4
+ class LinkedTo
5
+
6
+ # Set readers for the instance variables.
7
+ attr_accessor :name, :predicate, :options, :multivalued, :field_name, :class_name
8
+ alias_method :multivalued?, :multivalued
9
+
10
+ # Create the new link with a name and optional additional options.
11
+ def initialize(name, predicate, options = {})
12
+ @name = name
13
+ @options = options
14
+ @predicate = RDF::URI.new(predicate.to_s)
15
+ @multivalued = options[:multivalued] || false
16
+ @class_name = options[:class_name] || @name.to_s.classify
17
+ @field_name = options[:field_name] || (@name.to_s + ( @multivalued ? "_uris" : "_uri" )).to_sym
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,172 @@
1
+ # encoding: utf-8
2
+ require "tripod/links/linked_to"
3
+ require "tripod/links/linked_from"
4
+
5
+ # This module defines behaviour for fields.
6
+ module Tripod::Links
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :linked_tos
11
+ class_attribute :linked_froms
12
+ self.linked_tos = {}
13
+ self.linked_froms = {}
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ # Define a link to another resource. Creates relevant fields and getter/setter methods. Note that the getter only retrives saved resources from the db.
19
+ #
20
+ # @example Define a link away from resources of this class to resources of class Organisation
21
+ # linked_to :organisation, 'http://example.com/name'
22
+ #
23
+ # @example Define a multivalued link away from resources of this class (can be combined with other options)
24
+ # linked_to :organisations, 'http://example.com/modified_at', multivalued: true
25
+ #
26
+ # @example Define a link away from resources of this class, specifying the class and the field name that will be generated
27
+ # linked_to :org, 'http://example.com/modified_at', class_name: 'Organisation', field: my_field
28
+ #
29
+ # @param [ Symbol ] name The name of the link.
30
+ # @param [ String, RDF::URI ] predicate The predicate for the field.
31
+ # @param [ Hash ] options The options to pass to the field.
32
+ #
33
+ # @option options [ Boolean ] multivalued Is this a multi-valued field? Default is false.
34
+ # @option options [ String ] class_name The name of the class of resource which we're linking to (normally will derive this from the link name)
35
+ # @option options [ Symbol ] field_name the symbol of the field that will be generated (normally will just add _uri or _uris to the link name)
36
+ #
37
+ # @return [ LinkedTo ] The generated link
38
+ def linked_to(name, predicate, options = {})
39
+ add_linked_to(name, predicate, options)
40
+ end
41
+
42
+
43
+ # Define that another resource links to this one. Creates a getter with the name you specify.
44
+ # For this to work, the incoming class needs to define a linked_to relationship.
45
+ # Just creates the relevant getter which always return an array of objects.
46
+ #
47
+ # @example make a method called people which returns Dog objects, via the linked_to :owner field on Dog. We guess the class name based on the linked_from name.
48
+ #  linked_from :dogs, :owner
49
+ #
50
+ # @example make a method called doggies which returns Dog objects, via the linked_to :person field on Dog.
51
+ #  linked_from :doggies, :person, class_name: 'Dog'
52
+ #
53
+ # @param [ Symbol ] name The name of the link.
54
+ # @param [ Symbol ] incoming_field_name The name of the linked_to relationship on the other class
55
+ # @param [ Hash ] options The options to pass to the field.
56
+ #
57
+ # @option options [ String ] class_name The name of the class that links to this resource, if we can't guess it from the link name
58
+ #
59
+ # @return [ LinkedTo ] The generated link
60
+ def linked_from(name, incoming_field_name, options = {})
61
+ add_linked_from(name, incoming_field_name, options)
62
+ end
63
+
64
+ protected
65
+
66
+ def add_linked_to(name, predicate, options={})
67
+ link = linked_to_for(name, predicate, options)
68
+ linked_tos[name] = link
69
+
70
+ # create the field (always is_uri)
71
+ add_field(link.field_name, predicate, options.merge(is_uri: true))
72
+
73
+ create_linked_to_accessors(name, name)
74
+ end
75
+
76
+ def add_linked_from(name, incoming_field_name, options={})
77
+ link = linked_from_for(name, incoming_field_name, options)
78
+ linked_froms[name] = link
79
+
80
+ create_linked_from_getter(name, name, link)
81
+ end
82
+
83
+ def create_linked_to_accessors(name, meth)
84
+ link = linked_tos[name]
85
+
86
+ create_linked_to_getter(name, meth, link)
87
+ create_linked_to_setter(name, meth, link)
88
+ end
89
+
90
+ def create_linked_from_getter(name, meth, link)
91
+
92
+ generated_methods.module_eval do
93
+ re_define_method(meth) do
94
+ klass = Kernel.const_get(link.class_name)
95
+
96
+ incoming_link = klass.linked_tos[link.incoming_field_name.to_sym]
97
+ incoming_predicate = klass.fields[incoming_link.field_name].predicate
98
+
99
+ # note - this will only find saved ones.
100
+ klass
101
+ .where("?uri <#{incoming_predicate.to_s}> <#{self.uri.to_s}>")
102
+ .resources
103
+ end
104
+ end
105
+ end
106
+
107
+ def create_linked_to_getter(name, meth, link)
108
+
109
+ generated_methods.module_eval do
110
+ re_define_method(meth) do
111
+
112
+ klass = Kernel.eval(link.class_name)
113
+
114
+ if link.multivalued?
115
+
116
+ # # TODO: is there a more efficient way of doing this?
117
+
118
+ # note that we can't just do a query like this:
119
+ # `klass.where('<#{self.uri.to_s}> <#{predicate.to_s}> ?uri').resources`
120
+ # ... because this will only find saved ones and we want to find resources
121
+ # whose uris have been set on the resource but not saved to db yet.
122
+
123
+ criteria = klass.where('?uri ?p ?o')
124
+
125
+ uris = read_attribute(link.field_name)
126
+
127
+ filter_str = "FILTER("
128
+ if uris.any?
129
+ filter_str += uris.map {|u| "?uri = <#{u.to_s}>" }.join(" || ")
130
+ else
131
+ filter_str += "1 = 0"
132
+ end
133
+ filter_str += ")"
134
+
135
+ criteria.where(filter_str).resources
136
+ else
137
+ klass.find(read_attribute(link.field_name)) rescue nil #look it up by it's uri
138
+ end
139
+
140
+ end
141
+ end
142
+ end
143
+
144
+ def create_linked_to_setter(name, meth, link)
145
+
146
+ generated_methods.module_eval do
147
+ re_define_method("#{meth}=") do |value|
148
+
149
+ if link.multivalued?
150
+ val = value.to_a.map{ |v| v.uri }
151
+ write_attribute( link.field_name, val)
152
+ else
153
+ # set the uri from the passed in resource
154
+ write_attribute( link.field_name, value.uri )
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ # instantiates and returns a new LinkedFrom
161
+ def linked_from_for(name, incoming_field_name, options)
162
+ Tripod::Links::LinkedFrom.new(name, incoming_field_name, options)
163
+ end
164
+
165
+ # instantiates and returns a new LinkTo
166
+ def linked_to_for(name, predicate, options)
167
+ Tripod::Links::LinkedTo.new(name, predicate, options)
168
+ end
169
+
170
+ end
171
+
172
+ end
@@ -1,3 +1,3 @@
1
1
  module Tripod
2
- VERSION = "0.9.7"
2
+ VERSION = "0.9.8"
3
3
  end
data/lib/tripod.rb CHANGED
@@ -96,6 +96,7 @@ require "tripod/errors"
96
96
  require "tripod/repository"
97
97
  require "tripod/fields"
98
98
  require "tripod/criteria"
99
+ require "tripod/links"
99
100
  require "tripod/finders"
100
101
  require "tripod/persistence"
101
102
  require "tripod/eager_loading"
@@ -0,0 +1,17 @@
1
+ class Dog
2
+
3
+ include Tripod::Resource
4
+
5
+ rdf_type 'http://example.com/dog'
6
+ graph_uri 'http://example.com/graph'
7
+
8
+ field :name, 'http://example.com/name'
9
+
10
+ linked_to :owner, 'http://example.com/owner', class_name: 'Person'
11
+ linked_to :person, 'http://example.com/person'
12
+ linked_to :friends, 'http://example.com/friend', multivalued: true, class_name: 'Dog'
13
+ linked_to :previous_owner, 'http://example.com/prevowner', class_name: 'Person', field_name: :prev_owner_uri
14
+
15
+ linked_to :arch_enemy, 'http://example.com/archenemy', class_name: 'Dog'
16
+ linked_to :enemies, 'http://example.com/enemy', class_name: 'Dog'
17
+ end
@@ -12,6 +12,9 @@ class Person
12
12
  field :age, 'http://example.com/age', :datatype => RDF::XSD.integer
13
13
  field :important_dates, 'http://example.com/importantdates', :datatype => RDF::XSD.date, :multivalued => true
14
14
 
15
+ linked_from :owns_dogs, :owner, class_name: 'Dog'
16
+ linked_from :dogs, :person
17
+
15
18
  before_save :pre_save
16
19
  before_destroy :pre_destroy
17
20
 
@@ -0,0 +1,134 @@
1
+ require "spec_helper"
2
+
3
+ describe Tripod::Links do
4
+
5
+ let(:barry) do
6
+ b = Person.new('http://example.com/id/barry')
7
+ b.name = 'Barry'
8
+ b.save!
9
+ b
10
+ end
11
+
12
+ let(:gary) do
13
+ g = Person.new('http://example.com/id/gary')
14
+ g.name = 'Gary'
15
+ g.save!
16
+ g
17
+ end
18
+
19
+ let(:jonno) do
20
+ j = Person.new('http://example.com/id/jonno')
21
+ j.name = 'Jonno'
22
+ j.save!
23
+ j
24
+ end
25
+
26
+ let(:fido) do
27
+ d = Dog.new('http://example.com/id/fido')
28
+ d.name = "fido"
29
+ d.save!
30
+ d
31
+ end
32
+
33
+ let!(:spot) do
34
+ d = Dog.new('http://example.com/id/spot')
35
+ d.name = "spot"
36
+ d.owner = barry
37
+ d.save!
38
+ d
39
+ end
40
+
41
+ let!(:rover) do
42
+ d = Dog.new('http://example.com/id/rover')
43
+ d.name = 'Rover'
44
+ d.owner = barry
45
+ d.person = gary
46
+ d.previous_owner = jonno
47
+ d.save!
48
+ d
49
+ end
50
+
51
+
52
+ describe ".linked_from" do
53
+
54
+ context "class name is specified" do
55
+ it "creates a getter which returns the resources" do
56
+ barry.owns_dogs.to_a == [rover, spot]
57
+ end
58
+ end
59
+
60
+ context "class name is not specified" do
61
+ it "creates a getter which returns the resources of the right class, based on the link name" do
62
+ gary.dogs.to_a.should == [rover]
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ describe ".linked_to" do
69
+
70
+ it "creates a getter for the field, with a default name, which returns the uri" do
71
+ rover.owner_uri.should == barry.uri
72
+ end
73
+
74
+ it "creates a setter for the link" do
75
+ rover.owner = gary
76
+ rover.owner_uri.should == gary.uri
77
+ end
78
+
79
+ context 'the class name is specified' do
80
+ it "creates a getter for the link, which returns a resource of the right type" do
81
+ rover.owner.class.should == Person
82
+ rover.owner.should == barry
83
+ end
84
+ end
85
+
86
+ context 'the class name is not specified' do
87
+ it "creates a getter for the link, which automatically returns a resource of the right type (from link name)" do
88
+ rover.person.class.should == Person
89
+ rover.person.should == gary
90
+ end
91
+ end
92
+
93
+ context 'when the field name is set to an alternative field name' do
94
+ it "uses that for the field name" do
95
+ rover.prev_owner_uri.should == jonno.uri
96
+ end
97
+ end
98
+
99
+ context 'its a multivalued field' do
100
+ it "creates a getter and setter for multiple values, instantiating the right types of resource" do
101
+ rover.friends = [fido, spot]
102
+
103
+ rover.friends.each do |f|
104
+ f.class.should == Dog
105
+ end
106
+
107
+ rover.friends.length.should == 2
108
+
109
+ rover.friends.to_a.first.uri.should == fido.uri
110
+ rover.friends.to_a.last.uri.should == spot.uri
111
+ end
112
+
113
+ it "creates field getters and setters with the _uris suffix" do
114
+ rover.friends_uris = [fido.uri, spot.uri]
115
+ rover.friends_uris.should == [fido.uri, spot.uri]
116
+ end
117
+
118
+ end
119
+
120
+ context "when the value is not set for a link" do
121
+ context "single valued" do
122
+ it "should be nil" do
123
+ rover.arch_enemy.should be_nil
124
+ end
125
+ end
126
+
127
+ context "multivalued" do
128
+ it "should be nil" do
129
+ rover.enemies.should be_nil
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
data/tripod.gemspec CHANGED
@@ -19,7 +19,8 @@ Gem::Specification.new do |gem|
19
19
  gem.rubyforge_project = "tripod"
20
20
 
21
21
  gem.add_dependency "rest-client"
22
- gem.add_dependency "activemodel", "> 3.2"
22
+ gem.add_dependency "activemodel", "~> 3.2"
23
+ gem.add_dependency "activesupport", "~> 3.2"
23
24
  gem.add_dependency "equivalent-xml"
24
25
  gem.add_dependency "rdf", "~> 1.1"
25
26
  gem.add_dependency "rdf-rdfxml"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tripod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ric Roberts
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-06-19 00:00:00.000000000 Z
13
+ date: 2014-06-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client
@@ -30,14 +30,28 @@ dependencies:
30
30
  name: activemodel
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - ">"
33
+ - - "~>"
34
34
  - !ruby/object:Gem::Version
35
35
  version: '3.2'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - ">"
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '3.2'
43
+ - !ruby/object:Gem::Dependency
44
+ name: activesupport
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '3.2'
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
41
55
  - !ruby/object:Gem::Version
42
56
  version: '3.2'
43
57
  - !ruby/object:Gem::Dependency
@@ -207,6 +221,9 @@ files:
207
221
  - lib/tripod/fields/standard.rb
208
222
  - lib/tripod/finders.rb
209
223
  - lib/tripod/graphs.rb
224
+ - lib/tripod/links.rb
225
+ - lib/tripod/links/linked_from.rb
226
+ - lib/tripod/links/linked_to.rb
210
227
  - lib/tripod/locale/en.yml
211
228
  - lib/tripod/persistence.rb
212
229
  - lib/tripod/predicates.rb
@@ -220,6 +237,7 @@ files:
220
237
  - lib/tripod/streaming.rb
221
238
  - lib/tripod/validations/is_url.rb
222
239
  - lib/tripod/version.rb
240
+ - spec/app/models/dog.rb
223
241
  - spec/app/models/person.rb
224
242
  - spec/app/models/resource.rb
225
243
  - spec/spec_helper.rb
@@ -230,6 +248,7 @@ files:
230
248
  - spec/tripod/fields_spec.rb
231
249
  - spec/tripod/finders_spec.rb
232
250
  - spec/tripod/graphs_spec.rb
251
+ - spec/tripod/links_spec.rb
233
252
  - spec/tripod/memcached_cache_store_spec.rb
234
253
  - spec/tripod/persistence_spec.rb
235
254
  - spec/tripod/predicates_spec.rb
@@ -266,6 +285,7 @@ signing_key:
266
285
  specification_version: 4
267
286
  summary: Active Model style RDF ORM
268
287
  test_files:
288
+ - spec/app/models/dog.rb
269
289
  - spec/app/models/person.rb
270
290
  - spec/app/models/resource.rb
271
291
  - spec/spec_helper.rb
@@ -276,6 +296,7 @@ test_files:
276
296
  - spec/tripod/fields_spec.rb
277
297
  - spec/tripod/finders_spec.rb
278
298
  - spec/tripod/graphs_spec.rb
299
+ - spec/tripod/links_spec.rb
279
300
  - spec/tripod/memcached_cache_store_spec.rb
280
301
  - spec/tripod/persistence_spec.rb
281
302
  - spec/tripod/predicates_spec.rb