spira 0.5.0 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YmI4NjdiNmExYjA4YTc4MjQ0MzhiM2E0MmE3MWNmY2NhNDkwZGI0OA==
5
+ data.tar.gz: !binary |-
6
+ NTMzZGYyOWNjOWY0ODQ3ZGVhNjVkYjNhMDZjZTljN2ExMGU3Mzc1ZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MDJlZjY1MjZiNDNiOGMyYTE0YzJiYzU5MzBjMWEyY2I2NmE1NjBlNmY2Y2Jk
10
+ NDhhZjQxYTFkZDIzNTllMjdkNzgxMzI2OTdhZmM4M2I1OTIxY2RlYjNjZDhh
11
+ ZGE0OGU3NzQ0OTMyNzg1ZDI1Y2U4OWEyN2ZlMjk4ZjI0NTE1MjA=
12
+ data.tar.gz: !binary |-
13
+ ZTRhNWRkMGFmZDdhYWVmMzk1YjNmMWMyMzYzZjYxOWNkYTY3NTUyMTUyYzdm
14
+ ODE4NWM1YTFhNmZiYjRjN2YyMDYxYmZjZGQyY2VkZTA1NTU0NDAzYjA5ZGU5
15
+ NDc0YzU2NWFlNzNjZjA2MTJlMzRhMjUyYzhkNjIzYzIzMmZhMzM=
data/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  It's time to breathe life into your linked data.
4
4
 
5
+ ## Need Help? Use our Google Group
6
+
7
+ If you have any question on how to use Spira, please use the [Google Group ruby-rdf](https://groups.google.com/forum/#!forum/ruby-rdf).
8
+
5
9
  ## Synopsis
6
10
  Spira is a framework for using the information in [RDF.rb][] repositories as model
7
11
  objects. It gives you the ability to work in a resource-oriented way without
@@ -15,29 +19,32 @@ A changelog is available in the {file:CHANGES.md} file.
15
19
 
16
20
  ### Example
17
21
 
18
- class Person < Spira::Base
22
+ ```ruby
23
+ class Person < Spira::Base
19
24
 
20
- configure :base_uri => "http://example.org/example/people"
21
-
22
- property :name, :predicate => FOAF.name, :type => String
23
- property :age, :predicate => FOAF.age, :type => Integer
25
+ configure :base_uri => "http://example.org/example/people"
24
26
 
25
- end
27
+ property :name, :predicate => FOAF.name, :type => String
28
+ property :age, :predicate => FOAF.age, :type => Integer
29
+
30
+ end
31
+
32
+ Spira.repository = RDF::Repository.new
26
33
 
27
- bob = RDF::URI("http://example.org/people/bob").as(Person)
28
- bob.age = 15
29
- bob.name = "Bob Smith"
30
- bob.save!
34
+ bob = RDF::URI("http://example.org/people/bob").as(Person)
35
+ bob.age = 15
36
+ bob.name = "Bob Smith"
37
+ bob.save!
38
+
39
+ bob.each_statement {|s| puts s}
40
+ #=> RDF::Statement:0x80abb80c(<http://example.org/example/people/bob> <http://xmlns.com/foaf/0.1/name> "Bob Smith" .)
41
+ #=> RDF::Statement:0x80abb8fc(<http://example.org/example/people/bob> <http://xmlns.com/foaf/0.1/age> "15"^^<http://www.w3.org/2001/XMLSchema#integer> .)
42
+ ```
31
43
 
32
- bob.each_statement {|s| puts s}
33
- #=> RDF::Statement:0x80abb80c(<http://example.org/example/people/bob> <http://xmlns.com/foaf/0.1/name> "Bob Smith" .)
34
- #=> RDF::Statement:0x80abb8fc(<http://example.org/example/people/bob> <http://xmlns.com/foaf/0.1/age> "15"^^<http://www.w3.org/2001/XMLSchema#integer> .)
35
-
36
44
  ### Features
37
45
 
38
46
  * Extensible validations system
39
47
  * Extensible types system
40
- * Easy to use multiple data sources
41
48
  * Easy to adapt models to existing data
42
49
  * Open-world semantics
43
50
  * Objects are still RDF.rb-compatible enumerable objects
@@ -81,7 +88,7 @@ as possible, there are a few changes that you should be aware of:
81
88
  for such resource and will only persist its properties.
82
89
  Although this is how the original Spira behaves too, I thought I'd state it
83
90
  explicitly here before you start freaking out.
84
- * Configuration options "base_uri", "default_vocabulary" and "repository_name" are
91
+ * Configuration options "base_uri", "default_vocabulary" are
85
92
  now configured via "configure" method (see the examples below).
86
93
  * A couple of (not so) subtle changes:
87
94
  1) Global caching is gone. This means that "artist.works.first.artist" (reverse lookup)
@@ -101,35 +108,41 @@ To use Spira, define model classes for your RDF data. Spira classes include
101
108
  RDF, and thus have access to all `RDF::Vocabulary` classes and `RDF::URI`
102
109
  without the `RDF::` prefix. For example:
103
110
 
104
- require 'spira'
105
-
106
- class CD < Spira::Base
107
- configure :base_uri => 'http://example.org/cds'
108
- property :name, :predicate => DC.title, :type => XSD.string
109
- property :artist, :predicate => URI.new('http://example.org/vocab/artist'), :type => :artist
110
- end
111
+ ```ruby
112
+ require 'spira'
111
113
 
112
- class Artist < Spira::Base
113
- configure :base_uri => 'http://example.org/artists'
114
- property :name, :predicate => DC.title, :type => XSD.string
115
- has_many :cds, :predicate => URI.new('http://example.org/vocab/published_cd'), :type => XSD.string
116
- end
117
-
118
- Then use your model classes, in a way more or less similar to any number of ORMs:
119
-
120
- cd = CD.for("queens-greatest-hits")
121
- cd.name = "Queen's greatest hits"
122
- artist = Artist.for("queen")
123
- artist.name = "Queen"
124
-
125
- cd.artist = artist
126
- cd.save!
127
- artist.cds = [cd]
128
- artist.save!
129
-
130
- queen = Artist.for('queen')
131
- hits = CD.for 'queens-greatest-hits'
132
- hits.artist == artist == queen
114
+ class CD < Spira::Base
115
+ configure :base_uri => 'http://example.org/cds'
116
+ property :name, :predicate => DC.title, :type => XSD.string
117
+ property :artist, :predicate => URI.new('http://example.org/vocab/artist'), :type => :artist
118
+ end
119
+
120
+ class Artist < Spira::Base
121
+ configure :base_uri => 'http://example.org/artists'
122
+ property :name, :predicate => DC.title, :type => XSD.string
123
+ has_many :cds, :predicate => URI.new('http://example.org/vocab/published_cd'), :type => XSD.string
124
+ end
125
+ ```
126
+
127
+ Then define a Spira repository (see [Defining Repositories](#defining-repositories)) to use your model classes, in a way more or less similar to any number of ORMs:
128
+
129
+ ```ruby
130
+ Spira.repository = RDF::Repository.new
131
+
132
+ cd = CD.for("queens-greatest-hits")
133
+ cd.name = "Queen's greatest hits"
134
+ artist = Artist.for("queen")
135
+ artist.name = "Queen"
136
+
137
+ cd.artist = artist
138
+ cd.save!
139
+ artist.cds = [cd]
140
+ artist.save!
141
+
142
+ queen = Artist.for('queen')
143
+ hits = CD.for 'queens-greatest-hits'
144
+ hits.artist == artist == queen
145
+ ```
133
146
 
134
147
  ### URIs and Blank Nodes
135
148
 
@@ -138,17 +151,23 @@ Spira instances have a subject, which is either a URI or a blank node.
138
151
  A class with a base URI can instantiate with a string (or anything, via to_s),
139
152
  and it will have a URI representation:
140
153
 
141
- Artist.for('queen')
154
+ ```ruby
155
+ Artist.for('queen')
156
+ ```
142
157
 
143
158
  However, a class is not required to have a base URI, and even if it does, it
144
159
  can always access classes with a full URI:
145
160
 
146
- nk = Artist.for(RDF::URI.new('http://example.org/my-hidden-cds/new-kids'))
161
+ ```ruby
162
+ nk = Artist.for(RDF::URI.new('http://example.org/my-hidden-cds/new-kids'))
163
+ ```
147
164
 
148
165
  If you have a URI that you would like to look at as a Spira resource, you can instantiate it from the URI:
149
166
 
150
- RDF::URI.new('http://example.org/my-hidden-cds/new-kids').as(Artist)
151
- # => <Artist @subject=http://example.org/my-hidden-cds/new-kids>
167
+ ```ruby
168
+ RDF::URI.new('http://example.org/my-hidden-cds/new-kids').as(Artist)
169
+ # => <Artist @subject=http://example.org/my-hidden-cds/new-kids>
170
+ ```
152
171
 
153
172
  Any call to 'for' with a valid identifier will always return an object with nil
154
173
  fields. It's a way of looking at a given resource, not a closed-world mapping
@@ -156,16 +175,20 @@ to one.
156
175
 
157
176
  You can also use blank nodes more or less as you would a URI:
158
177
 
159
- remix_artist = Artist.for(RDF::Node.new)
160
- # => <Artist @subject=#<RDF::Node:0xd1d314(_:g13751060)>>
161
- RDF::Node.new.as(Artist)
162
- # => <Artist @subject=#<RDF::Node:0xd1d314(_:g13751040)>>
178
+ ```ruby
179
+ remix_artist = Artist.for(RDF::Node.new)
180
+ # => <Artist @subject=#<RDF::Node:0xd1d314(_:g13751060)>>
181
+ RDF::Node.new.as(Artist)
182
+ # => <Artist @subject=#<RDF::Node:0xd1d314(_:g13751040)>>
183
+ ```
163
184
 
164
185
  Finally, you can create an instance of a Spira projection with #new, and you'll
165
186
  get an instance with a shiny new blank node subject:
166
187
 
167
- formerly_known_as_prince = Artist.new
168
- # => <Artist @subject=#<RDF::Node:0xd1d314(_:g13747140)>>
188
+ ```ruby
189
+ formerly_known_as_prince = Artist.new
190
+ # => <Artist @subject=#<RDF::Node:0xd1d314(_:g13747140)>>
191
+ ```
169
192
 
170
193
  ### Class Options
171
194
 
@@ -177,38 +200,50 @@ A class with a `base_uri` set (either an `RDF::URI` or a `String`) will
177
200
  use that URI as a base URI for non-absolute `for` calls.
178
201
 
179
202
  Example
180
- CD.for 'queens-greatest-hits' # is the same as...
181
- CD.for RDF::URI.new('http://example.org/cds/queens-greatest-hits')
203
+ ```ruby
204
+ CD.for 'queens-greatest-hits' # is the same as...
205
+ CD.for RDF::URI.new('http://example.org/cds/queens-greatest-hits')
206
+ ```
182
207
 
183
208
  #### type
184
209
 
185
210
  A class with a `type` set is assigned an `RDF.type` on creation and saving.
186
211
 
187
- class Album < Spira::Base
188
- type URI.new('http://example.org/types/album')
189
- property :name, :predicate => DC.title
190
- end
212
+ ```ruby
213
+ class Album < Spira::Base
214
+ type URI.new('http://example.org/types/album')
215
+ property :name, :predicate => DC.title
216
+ end
191
217
 
192
- rolling_stones = Album.for RDF::URI.new('http://example.org/cds/rolling-stones-hits')
193
- # See RDF.rb at http://rdf.rubyforge.org/RDF/Enumerable.html for more information about #has_predicate?
194
- rolling_stones.has_predicate?(RDF.type) #=> true
195
- Album.type #=> RDF::URI('http://example.org/types/album')
218
+ Spira.repository = RDF::Repository.new
219
+
220
+ rolling_stones = Album.for RDF::URI.new('http://example.org/cds/rolling-stones-hits')
221
+ # See RDF.rb at http://rdf.rubyforge.org/RDF/Enumerable.html for more information about #has_predicate?
222
+ rolling_stones.has_predicate?(RDF.type) #=> true
223
+ Album.type #=> RDF::URI('http://example.org/types/album')
224
+ `
196
225
 
197
226
  In addition, one can count the members of a class with a `type` defined:
198
227
 
199
- Album.count #=> 1
228
+ ```ruby
229
+ Album.count #=> 1
230
+ ```
200
231
 
201
232
 
202
233
  It is possible to assign multiple types to a Spira class:
203
234
 
204
- class Man < Spira::Base
205
- type RDF::URI.new('http://example.org/people/father')
206
- type RDF::URI.new('http://example.org/people/cop')
207
- end
235
+ ```ruby
236
+ class Man < Spira::Base
237
+ type RDF::URI.new('http://example.org/people/father')
238
+ type RDF::URI.new('http://example.org/people/cop')
239
+ end
240
+ ```
208
241
 
209
242
  All assigned types are accessible via "types":
210
243
 
211
- Man.types #=> #<Set: {#<RDF::URI:0xd5ebc0(http://example.org/people/father)>, #<RDF::URI:0xd5e4b8(http://example.org/people/cop)>}>
244
+ ```ruby
245
+ Man.types #=> #<Set: {#<RDF::URI:0xd5ebc0(http://example.org/people/father)>, #<RDF::URI:0xd5e4b8(http://example.org/people/cop)>}>
246
+ ```
212
247
 
213
248
  Also note that "type" actually returns a first type from the list of types.
214
249
 
@@ -225,30 +260,23 @@ A class declares list members with the `has_many` function. See `Property Optio
225
260
 
226
261
  A class with a `default_vocabulary` set will transparently create predicates for defined properties:
227
262
 
228
- class Song < Spira::Base
229
- configure :default_vocabulary => URI.new('http://example.org/vocab'),
230
- :base_uri => 'http://example.org/songs'
231
- property :title
232
- property :author, :type => :artist
233
- end
263
+ ```ruby
264
+ class Song < Spira::Base
265
+ configure :default_vocabulary => URI.new('http://example.org/vocab'),
266
+ :base_uri => 'http://example.org/songs'
267
+ property :title
268
+ property :author, :type => :artist
269
+ end
234
270
 
235
- dancing_queen = Song.for 'dancing-queen'
236
- dancing_queen.title = "Dancing Queen"
237
- dancing_queen.artist = abba
238
- # See RDF::Enumerable for #has_predicate?
239
- dancing_queen.has_predicate?(RDF::URI.new('http://example.org/vocab/title')) #=> true
240
- dancing_queen.has_predicate?(RDF::URI.new('http://example.org/vocab/artist')) #=> true
271
+ Spira.repository = RDF::Repository.new
241
272
 
242
- #### repository_name
243
-
244
- Provides this class with a default repository to use instead of the `:default`
245
- repository if one is not set.
246
-
247
- class Song < Spira::Base
248
- configure :repository_name => :songs
249
- end
250
-
251
- See 'Defining Repositories' for more information.
273
+ dancing_queen = Song.for 'dancing-queen'
274
+ dancing_queen.title = "Dancing Queen"
275
+ dancing_queen.artist = abba
276
+ # See RDF::Enumerable for #has_predicate?
277
+ dancing_queen.has_predicate?(RDF::URI.new('http://example.org/vocab/title')) #=> true
278
+ dancing_queen.has_predicate?(RDF::URI.new('http://example.org/vocab/artist')) #=> true
279
+ ```
252
280
 
253
281
  ### Property Options
254
282
 
@@ -268,6 +296,32 @@ Property always takes a symbol name as a name, and a variable list of options.
268
296
  **Types** below. Default: `Any`
269
297
  * `:predicate`: The predicate to use for this type. This can be any RDF URI.
270
298
  This option is required unless the `default_vocabulary` has been used.
299
+ * `:localized`: Indicates if the property is multilingual. See 'Localized Properties'
300
+
301
+ #### Localized Properties
302
+
303
+ A localized property allows to define a value per language. It only works with
304
+ properties having a single item, ie defined with `property`.
305
+
306
+ ```ruby
307
+ class Article < Spira::Base
308
+ property :label, :localized => true
309
+ end
310
+
311
+ Spira.repository = RDF::Repository.new
312
+
313
+ # default locale :en
314
+ random_article = Article.for 'random-article'
315
+ random_article.label = "A label in english"
316
+ i18n.locale = :fr
317
+ random_article.label = "Un libellé en français"
318
+
319
+ random_article.label_native
320
+ # #=> [#<RDF::Literal:0xdb47c8("A label in english"@en)>, #<RDF::Literal:0xe5c3d8("Un libellé en français"@fr)>]
321
+
322
+ random_article.label_with_locales
323
+ # #=> {:en=>"A label in english", :fr=>"Un libellé en français"}
324
+ ```
271
325
 
272
326
  ### Types
273
327
 
@@ -288,29 +342,33 @@ A type class includes Spira::Type, and can implement serialization and
288
342
  deserialization functions, and register aliases to themselves if their datatype
289
343
  is usually expressed as a URI. Here is the built-in Spira Integer class:
290
344
 
291
- module Spira::Types
292
- class Integer
293
-
294
- include Spira::Type
295
-
296
- def self.unserialize(value)
297
- value.object
298
- end
299
-
300
- def self.serialize(value)
301
- RDF::Literal.new(value)
302
- end
303
-
304
- register_alias RDF::XSD.integer
305
- end
345
+ ```ruby
346
+ module Spira::Types
347
+ class Integer
348
+
349
+ include Spira::Type
350
+
351
+ def self.unserialize(value)
352
+ value.object
353
+ end
354
+
355
+ def self.serialize(value)
356
+ RDF::Literal.new(value)
306
357
  end
307
358
 
359
+ register_alias RDF::XSD.integer
360
+ end
361
+ end
362
+ ```
363
+
308
364
  Classes can now use this particular type like so:
309
365
 
310
- class Test < Spira::Base
311
- property :test1, :type => Integer
312
- property :test2, :type => RDF::XSD.integer
313
- end
366
+ ```ruby
367
+ class Test < Spira::Base
368
+ property :test1, :type => Integer
369
+ property :test2, :type => RDF::XSD.integer
370
+ end
371
+ ```
314
372
 
315
373
  Spira classes include the Spira::Types namespace, where several default types
316
374
  are implemented:
@@ -328,55 +386,67 @@ The default type for a Spira property is `Spira::Types::Any`, which uses
328
386
  You can implement your own types as well. Your class' serialize method should
329
387
  turn an RDF::Value into a ruby object, and vice versa.
330
388
 
331
- module MyModule
332
- class MyType
333
- include Spira::Type
334
- def self.serialize(value)
335
- ...
336
- end
337
-
338
- def self.unserialize(value)
339
- ...
340
- end
341
- end
389
+ ```ruby
390
+ module MyModule
391
+ class MyType
392
+ include Spira::Type
393
+ def self.serialize(value)
394
+ ...
342
395
  end
343
396
 
344
- class MyClass < Spira::Base
345
- property :property1, :type => MyModule::MyType
397
+ def self.unserialize(value)
398
+ ...
346
399
  end
400
+ end
401
+ end
402
+
403
+ class MyClass < Spira::Base
404
+ property :property1, :type => MyModule::MyType
405
+ end
406
+ ```
347
407
 
348
408
  ## Defining Repositories
349
409
 
350
- You can define multiple repositories with Spira, and use more than one at a time:
410
+ You can work on any kind of RDF::Repository with Spira:
351
411
 
352
- require 'rdf/ntriples'
353
- require 'rdf/sesame'
354
- Spira.add_repository! :cds, RDF::Sesame::Repository.new 'some_server'
355
- Spira.add_repository! :albums, RDF::Repository.load('some_file.nt')
412
+ ```ruby
413
+ require 'rdf/ntriples'
414
+ require 'rdf/sesame'
356
415
 
357
- class CD < Spira::Base
358
- configure :repository_name => :cds
359
- end
360
- class Album < Spira::Base
361
- configure :repository_name => :albums
362
- end
416
+ class Album < Spira::Base
417
+ end
363
418
 
364
- Objects can reference each other cross-repository.
419
+ Spira.repository = RDF::Sesame::Repository.new 'some_server'
420
+ ...
365
421
 
366
- If no repository has been specified, the `:default` repository will be used.
422
+ Spira.repository = RDF::Repository.load('some_file.nt')
423
+ ...
367
424
 
368
- repo = RDF::Repository.new
369
- Spira.add_repository! :default, repo
370
- Artist.repository == repo #=> true
425
+ Spira.using_repository(RDF::Repository.load('some_file.nt')) do
426
+ ...
427
+ end
428
+ ```
371
429
 
372
- Classes can specify a default repository to use other than `:default` with the
373
- `repository_name` function:
430
+ Spira.repository is thread-safe, which means that each thread stores its own instance.
431
+ It allows you to work on multiple repositories at the same time:
374
432
 
375
- class Song < Spira::Base
376
- configure :repository_name => :songs
377
- end
433
+ ```ruby
434
+ threads = []
435
+ repositories = [RDF::Repository.new, RDF::Repository.new, RDF::Repository.new]
436
+
437
+ repositories.each do |repository|
438
+ threads << Thread.new(repository) do |repository|
439
+ Spira.repository = repository
440
+
441
+ album = Album.for("http://theperson.com/album/random_name")
442
+ album.year = 1950 + (rand*100).to_i
443
+ album.save!
444
+ end
445
+ end
378
446
 
379
- Song.repository #=> nil, won't use :default
447
+ threads.map(&:join)
448
+ repositories.map(&:size).join(', ') # 1, 1, 1
449
+ ```
380
450
 
381
451
  ## Validations
382
452
 
@@ -408,8 +478,19 @@ Spira is free and unemcumbered software released into the public
408
478
  domain. For more information, see the included UNLICENSE file.
409
479
 
410
480
  ## Contributing
411
- Fork it on Github and go. Please make sure you're kosher with the UNLICENSE
412
- file before contributing.
481
+ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration.
482
+
483
+ * Do your best to adhere to the existing coding conventions and idioms.
484
+ * Don't use hard tabs, and don't leave trailing whitespace on any line.
485
+ * Do document every method you add using [YARD][] annotations. Read the
486
+ [tutorial][YARD-GS] or just look at the existing code for examples.
487
+ * Don't touch the `.gemspec`, `VERSION` or `AUTHORS` files. If you need to
488
+ change them, do so on your private branch only.
489
+ * Do feel free to add yourself to the `CREDITS` file and the corresponding
490
+ list in the the `README`. Alphabetical order applies.
491
+ * Do note that in order for us to merge any non-trivial changes (as a rule
492
+ of thumb, additions larger than about 15 lines of code), we need an
493
+ explicit [public domain dedication][PDD] on record from you.
413
494
 
414
495
  [public-rdf-ruby w3c mailing list]: http://lists.w3.org/Archives/Public/public-rdf-ruby/
415
- [RDF.rb]: http://rdf.rubyforge.org
496
+ [RDF.rb]: http://rubygems.org/gems/rdf
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.0
data/lib/spira/base.rb CHANGED
@@ -323,6 +323,35 @@ module Spira
323
323
  end
324
324
  end
325
325
 
326
+ ## Localized properties functions
327
+
328
+ def merge_localized_property(name, arg)
329
+ values = read_attribute("#{name}_native")
330
+ values.delete_if { |s| s.language == I18n.locale }
331
+ values << serialize_localized_property(arg, I18n.locale)
332
+ values
333
+ end
334
+
335
+ def serialize_localized_property(value, locale)
336
+ RDF::Literal.new(value, :language => locale)
337
+ end
338
+
339
+ def unserialize_localized_properties(values, locale)
340
+ v = values.detect { |s| s.language == locale || s.simple? }
341
+ v && v.object
342
+ end
343
+
344
+ def hash_localized_properties(values)
345
+ values.inject({}) do |out, v|
346
+ out[v.language] = v.object
347
+ out
348
+ end
349
+ end
350
+
351
+ def serialize_hash_localized_properties(values)
352
+ values.map { |lang, property| RDF::Literal.new(property, :language => lang) }
353
+ end
354
+
326
355
  # Build a Ruby value from an RDF value.
327
356
  def build_value(node, type)
328
357
  klass = classize_resource(type)
@@ -3,22 +3,13 @@ module Spira
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
- ##
7
- # Repository name for this class
8
- #
9
- # @return [Symbol]
10
- def repository_name
11
- # should be redefined in children, if required
12
- # see also Spira::Resource.configure :repository option
13
- :default
14
- end
15
6
 
16
7
  ##
17
8
  # The current repository for this class
18
9
  #
19
10
  # @return [RDF::Repository, nil]
20
11
  def repository
21
- Spira.repository(repository_name)
12
+ Spira.repository || raise(NoRepositoryError)
22
13
  end
23
14
 
24
15
  ##
@@ -233,11 +224,6 @@ module Spira
233
224
  when identifier.respond_to?(:to_uri) && !identifier.is_a?(RDF::URI)
234
225
  id_for(identifier.to_uri)
235
226
  # see comment with #to_uri above, this might be a fragment
236
- when identifier.is_a?(Addressable::URI)
237
- id_for(RDF::URI.intern(identifier))
238
- # This is a #to_s or a URI fragment with a base uri. We'll treat them the same.
239
- # FIXME: when #/ makes it into RDF.rb proper, this can all be wrapped
240
- # into the one case statement above.
241
227
  else
242
228
  uri = identifier.is_a?(RDF::URI) ? identifier : RDF::URI.intern(identifier.to_s)
243
229
  case
@@ -377,13 +363,10 @@ module Spira
377
363
  # This resource will block if the underlying repository
378
364
  # blocks the next time it accesses attributes.
379
365
  #
380
- # If repository is not defined, the attributes are just not set,
381
- # instead of raising a Spira::NoRepositoryError.
382
- #
383
366
  # NB: "props" argument is ignored, it is handled in Base
384
367
  #
385
368
  def reload(props = {})
386
- sts = self.class.repository && self.class.repository.query(:subject => subject)
369
+ sts = self.class.repository.query(:subject => subject)
387
370
  self.class.properties.each do |name, options|
388
371
  name = name.to_s
389
372
  if sts
@@ -7,7 +7,6 @@ module Spira
7
7
  # Configuration options for the Spira::Resource:
8
8
  #
9
9
  # @params[Hash] options
10
- # :repository_name :: name of the repository to use
11
10
  # :base_uri :: base URI to be used for the resource
12
11
  # :default_vocabulary :: default vocabulary to use for the properties
13
12
  # defined for this resource
@@ -16,8 +15,7 @@ module Spira
16
15
  #
17
16
  def configure(options = {})
18
17
  singleton_class.class_eval do
19
- { :repository_name => options[:repository_name],
20
- :base_uri => options[:base_uri],
18
+ { :base_uri => options[:base_uri],
21
19
  :default_vocabulary => options[:default_vocabulary]
22
20
  }.each do |name, value|
23
21
  # redefine reader methods only when required,
@@ -80,17 +78,23 @@ module Spira
80
78
  # @see Spira::Type
81
79
  # @return [Void]
82
80
  def property(name, opts = {})
83
- unset_has_many(name)
84
- predicate = predicate_for(opts[:predicate], name)
85
- type = type_for(opts[:type])
86
- properties[name] = HashWithIndifferentAccess.new(:predicate => predicate, :type => type)
81
+ if opts.delete(:localized)
82
+ raise 'Only Spira::Types::Any properties can accept the :localized option' unless type_for(opts[:type]) == Spira::Types::Any
83
+ define_localized_property_methods(name, opts)
84
+ has_many "#{name}_native", opts.merge(:type => Spira::Types::Native)
85
+ else
86
+ unset_has_many(name)
87
+ predicate = predicate_for(opts[:predicate], name)
88
+ type = type_for(opts[:type])
89
+ properties[name] = HashWithIndifferentAccess.new(:predicate => predicate, :type => type)
87
90
 
88
- define_attribute_method name
89
- define_method "#{name}=" do |arg|
90
- write_attribute name, arg
91
- end
92
- define_method name do
93
- read_attribute name
91
+ define_attribute_method name
92
+ define_method "#{name}=" do |arg|
93
+ write_attribute name, arg
94
+ end
95
+ define_method name do
96
+ read_attribute name
97
+ end
94
98
  end
95
99
  end
96
100
 
@@ -120,7 +124,6 @@ module Spira
120
124
  end
121
125
  end
122
126
 
123
-
124
127
  private
125
128
 
126
129
  # Unset a has_many relation if it exists. Allow to redefine the cardinality of a relation in a subClass
@@ -134,6 +137,32 @@ module Spira
134
137
  end
135
138
  end
136
139
 
140
+ ##
141
+ # Create the localized specific getter/setter for a given property
142
+ #
143
+ # @private
144
+ def define_localized_property_methods(name, opts)
145
+ define_method "#{name}=" do |arg|
146
+ new_value = merge_localized_property(name, arg)
147
+ write_attribute "#{name}_native", new_value
148
+ end
149
+
150
+ define_method name do
151
+ value = read_attribute("#{name}_native")
152
+ unserialize_localized_properties(value, I18n.locale)
153
+ end
154
+
155
+ define_method "#{name}_with_locales" do
156
+ value = read_attribute("#{name}_native")
157
+ hash_localized_properties(value)
158
+ end
159
+
160
+ define_method "#{name}_with_locales=" do |arg|
161
+ value = serialize_hash_localized_properties(arg)
162
+ write_attribute "#{name}_native", value
163
+ end
164
+ end
165
+
137
166
  ##
138
167
  # Determine the predicate for a property based on the given predicate, name, and default vocabulary
139
168
  #
data/lib/spira.rb CHANGED
@@ -12,11 +12,6 @@ require "spira/utils"
12
12
  # @see http://github.com/bhuga/spira
13
13
  # @see Spira::Resource
14
14
 
15
- module RDF
16
- class Repository
17
- end
18
- end
19
-
20
15
  module Spira
21
16
 
22
17
  autoload :Base, 'spira/base'
@@ -35,73 +30,51 @@ module Spira
35
30
  module_function :types
36
31
 
37
32
  ##
38
- # Add a repository to Spira's list of repositories.
39
- #
40
- # @overload add_repository(name, repo)
41
- # @param [Symbol] name The name of this repository
42
- # @param [RDF::Repository] repo
33
+ # The RDF::Repository used (reader)
43
34
  #
44
- # @overload add_repository(name, klass, *args)
45
- # @param [Symbol] name The name of this repository
46
- # @param [Class] klass
47
- # A Class that inherits from `RDF::Repository`
48
- # @param [Array] args
49
- # The list of arguments to instantiate the class
50
- #
51
- # @example Adding an ntriples file as a repository
52
- # Spira.add_repository(:default, RDF::Repository.load('http://datagraph.org/jhacker/foaf.nt'))
53
- # @example Adding an empty repository to be instantiated on use
54
- # Spira.add_repository(:default, RDF::Repository)
55
- # @return [Void]
56
- def add_repository(name, klass, *args)
57
- repositories[name] =
58
- case klass
59
- when Class
60
- promise { klass.new(*args) }
61
- else
62
- klass
63
- end
64
- if (name == :default) && repository(name).nil?
65
- warn "WARNING: Adding nil default repository"
66
- end
35
+ # @return [RDF::Repository]
36
+ # @see RDF::Repository
37
+ def repository
38
+ Thread.current[:repository]
67
39
  end
68
- alias_method :add_repository!, :add_repository
69
- module_function :add_repository, :add_repository!
40
+ module_function :repository
70
41
 
71
42
  ##
72
- # The RDF::Repository for the named repository
43
+ # The RDF::Repository used (reader)
73
44
  #
74
- # @param [Symbol] name The name of the repository
75
45
  # @return [RDF::Repository]
76
46
  # @see RDF::Repository
77
- def repository(name)
78
- repositories[name]
47
+ def repository=(repository)
48
+ Thread.current[:repository] = repository
79
49
  end
80
- module_function :repository
50
+ module_function :repository=
81
51
 
82
52
  ##
83
- # Clear all repositories from Spira's knowledge. Use it if you want, but
53
+ # Clear the repository from Spira's knowledge. Use it if you want, but
84
54
  # it's really here for testing.
85
55
  #
86
56
  # @return [Void]
87
57
  # @private
88
- def clear_repositories!
89
- @repositories = {}
58
+ def clear_repository!
59
+ Spira.repository = nil
90
60
  end
91
- module_function :clear_repositories!
92
-
93
-
94
- private
61
+ module_function :clear_repository!
95
62
 
96
- ##
97
- # The list of repositories available for Spira resources
63
+ # Execute a block on a specific repository
98
64
  #
99
- # @see http://rdf.rubyforge.org/RDF/Repository.html
100
- # @return [Hash{Symbol => RDF::Repository}]
101
- def repositories
102
- @repositories ||= {}
65
+ # @param [RDF::Repository] repository the repository to work on
66
+ # @param [Symbol] name the repository name
67
+ # @yield the block with the instructions while using the repository
68
+ def using_repository(repo)
69
+ old_repository = Spira.repository
70
+ Spira.repository = repo
71
+ yield if block_given?
72
+ ensure
73
+ Spira.repository = old_repository
103
74
  end
104
- module_function :repositories
75
+ module_function :using_repository
76
+
77
+ private
105
78
 
106
79
  ##
107
80
  # Alias a property type to another. This allows a range of options to be
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spira
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
5
- prerelease:
4
+ version: '0.7'
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ben Lavender
@@ -10,196 +9,186 @@ autorequire:
10
9
  bindir:
11
10
  - bin
12
11
  cert_chain: []
13
- date: 2013-03-01 00:00:00.000000000 Z
12
+ date: 2013-12-09 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
- name: rdf-spec
15
+ name: bundler
16
+ type: :development
17
17
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
18
  requirements:
20
19
  - - ~>
21
20
  - !ruby/object:Gem::Version
22
21
  version: '1.0'
23
- type: :development
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
25
  - - ~>
29
26
  - !ruby/object:Gem::Version
30
27
  version: '1.0'
31
28
  - !ruby/object:Gem::Dependency
32
- name: rspec
29
+ name: rdf-spec
30
+ type: :development
33
31
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
32
  requirements:
36
33
  - - ~>
37
34
  - !ruby/object:Gem::Version
38
- version: 2.12.0
35
+ version: '1.1'
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '1.1'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
39
44
  type: :development
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: 2.14.0
40
50
  prerelease: false
41
51
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
52
  requirements:
44
53
  - - ~>
45
54
  - !ruby/object:Gem::Version
46
- version: 2.12.0
55
+ version: 2.14.0
47
56
  - !ruby/object:Gem::Dependency
48
57
  name: yard
58
+ type: :development
49
59
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
60
  requirements:
52
61
  - - ~>
53
62
  - !ruby/object:Gem::Version
54
63
  version: 0.8.3
55
- type: :development
56
64
  prerelease: false
57
65
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
66
  requirements:
60
67
  - - ~>
61
68
  - !ruby/object:Gem::Version
62
69
  version: 0.8.3
63
70
  - !ruby/object:Gem::Dependency
64
71
  name: redcarpet
72
+ type: :development
65
73
  requirement: !ruby/object:Gem::Requirement
66
- none: false
67
74
  requirements:
68
75
  - - ~>
69
76
  - !ruby/object:Gem::Version
70
77
  version: 2.2.2
71
- type: :development
72
78
  prerelease: false
73
79
  version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
80
  requirements:
76
81
  - - ~>
77
82
  - !ruby/object:Gem::Version
78
83
  version: 2.2.2
79
84
  - !ruby/object:Gem::Dependency
80
85
  name: guard
86
+ type: :development
81
87
  requirement: !ruby/object:Gem::Requirement
82
- none: false
83
88
  requirements:
84
89
  - - ~>
85
90
  - !ruby/object:Gem::Version
86
91
  version: 1.2.3
87
- type: :development
88
92
  prerelease: false
89
93
  version_requirements: !ruby/object:Gem::Requirement
90
- none: false
91
94
  requirements:
92
95
  - - ~>
93
96
  - !ruby/object:Gem::Version
94
97
  version: 1.2.3
95
98
  - !ruby/object:Gem::Dependency
96
99
  name: guard-rspec
100
+ type: :development
97
101
  requirement: !ruby/object:Gem::Requirement
98
- none: false
99
102
  requirements:
100
103
  - - ~>
101
104
  - !ruby/object:Gem::Version
102
105
  version: 1.1.0
103
- type: :development
104
106
  prerelease: false
105
107
  version_requirements: !ruby/object:Gem::Requirement
106
- none: false
107
108
  requirements:
108
109
  - - ~>
109
110
  - !ruby/object:Gem::Version
110
111
  version: 1.1.0
111
112
  - !ruby/object:Gem::Dependency
112
113
  name: guard-ctags-bundler
114
+ type: :development
113
115
  requirement: !ruby/object:Gem::Requirement
114
- none: false
115
116
  requirements:
116
117
  - - ~>
117
118
  - !ruby/object:Gem::Version
118
119
  version: 0.1.1
119
- type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
- none: false
123
122
  requirements:
124
123
  - - ~>
125
124
  - !ruby/object:Gem::Version
126
125
  version: 0.1.1
127
126
  - !ruby/object:Gem::Dependency
128
127
  name: rdf
128
+ type: :runtime
129
129
  requirement: !ruby/object:Gem::Requirement
130
- none: false
131
130
  requirements:
132
131
  - - ~>
133
132
  - !ruby/object:Gem::Version
134
- version: '1.0'
135
- type: :runtime
133
+ version: '1.1'
136
134
  prerelease: false
137
135
  version_requirements: !ruby/object:Gem::Requirement
138
- none: false
139
136
  requirements:
140
137
  - - ~>
141
138
  - !ruby/object:Gem::Version
142
- version: '1.0'
139
+ version: '1.1'
143
140
  - !ruby/object:Gem::Dependency
144
141
  name: rdf-isomorphic
142
+ type: :runtime
145
143
  requirement: !ruby/object:Gem::Requirement
146
- none: false
147
144
  requirements:
148
145
  - - ~>
149
146
  - !ruby/object:Gem::Version
150
- version: '1.0'
151
- type: :runtime
147
+ version: '1.1'
152
148
  prerelease: false
153
149
  version_requirements: !ruby/object:Gem::Requirement
154
- none: false
155
150
  requirements:
156
151
  - - ~>
157
152
  - !ruby/object:Gem::Version
158
- version: '1.0'
153
+ version: '1.1'
159
154
  - !ruby/object:Gem::Dependency
160
155
  name: promise
156
+ type: :runtime
161
157
  requirement: !ruby/object:Gem::Requirement
162
- none: false
163
158
  requirements:
164
159
  - - ~>
165
160
  - !ruby/object:Gem::Version
166
161
  version: 0.3.0
167
- type: :runtime
168
162
  prerelease: false
169
163
  version_requirements: !ruby/object:Gem::Requirement
170
- none: false
171
164
  requirements:
172
165
  - - ~>
173
166
  - !ruby/object:Gem::Version
174
167
  version: 0.3.0
175
168
  - !ruby/object:Gem::Dependency
176
169
  name: activemodel
170
+ type: :runtime
177
171
  requirement: !ruby/object:Gem::Requirement
178
- none: false
179
172
  requirements:
180
173
  - - ~>
181
174
  - !ruby/object:Gem::Version
182
175
  version: '3'
183
- type: :runtime
184
176
  prerelease: false
185
177
  version_requirements: !ruby/object:Gem::Requirement
186
- none: false
187
178
  requirements:
188
179
  - - ~>
189
180
  - !ruby/object:Gem::Version
190
181
  version: '3'
191
182
  - !ruby/object:Gem::Dependency
192
183
  name: activesupport
184
+ type: :runtime
193
185
  requirement: !ruby/object:Gem::Requirement
194
- none: false
195
186
  requirements:
196
187
  - - ~>
197
188
  - !ruby/object:Gem::Version
198
189
  version: '3'
199
- type: :runtime
200
190
  prerelease: false
201
191
  version_requirements: !ruby/object:Gem::Requirement
202
- none: false
203
192
  requirements:
204
193
  - - ~>
205
194
  - !ruby/object:Gem::Version
@@ -215,62 +204,62 @@ files:
215
204
  - AUTHORS
216
205
  - README.md
217
206
  - UNLICENSE
218
- - lib/rdf/ext/uri.rb
219
- - lib/spira/association_reflection.rb
220
- - lib/spira/base.rb
207
+ - VERSION
208
+ - lib/spira.rb
209
+ - lib/spira/validations.rb
210
+ - lib/spira/resource.rb
211
+ - lib/spira/types.rb
221
212
  - lib/spira/exceptions.rb
222
- - lib/spira/persistence.rb
223
213
  - lib/spira/reflections.rb
224
- - lib/spira/resource.rb
225
- - lib/spira/serialization.rb
226
- - lib/spira/type.rb
227
- - lib/spira/types/any.rb
228
- - lib/spira/types/boolean.rb
229
- - lib/spira/types/date.rb
230
- - lib/spira/types/dateTime.rb
214
+ - lib/spira/version.rb
215
+ - lib/spira/validations/uniqueness.rb
216
+ - lib/spira/base.rb
217
+ - lib/spira/association_reflection.rb
218
+ - lib/spira/utils.rb
219
+ - lib/spira/types/native.rb
231
220
  - lib/spira/types/decimal.rb
232
- - lib/spira/types/float.rb
221
+ - lib/spira/types/string.rb
222
+ - lib/spira/types/nonPositiveInteger.rb
233
223
  - lib/spira/types/gYear.rb
234
- - lib/spira/types/int.rb
235
- - lib/spira/types/integer.rb
236
- - lib/spira/types/long.rb
237
- - lib/spira/types/native.rb
238
224
  - lib/spira/types/negativeInteger.rb
225
+ - lib/spira/types/date.rb
226
+ - lib/spira/types/boolean.rb
239
227
  - lib/spira/types/nonNegativeInteger.rb
240
- - lib/spira/types/nonPositiveInteger.rb
228
+ - lib/spira/types/float.rb
241
229
  - lib/spira/types/positiveInteger.rb
242
- - lib/spira/types/string.rb
230
+ - lib/spira/types/any.rb
231
+ - lib/spira/types/integer.rb
232
+ - lib/spira/types/int.rb
243
233
  - lib/spira/types/uri.rb
244
- - lib/spira/types.rb
245
- - lib/spira/utils.rb
246
- - lib/spira/validations/uniqueness.rb
247
- - lib/spira/validations.rb
248
- - lib/spira/version.rb
249
- - lib/spira.rb
250
- homepage: http://spira.rubyforge.org
234
+ - lib/spira/types/dateTime.rb
235
+ - lib/spira/types/long.rb
236
+ - lib/spira/serialization.rb
237
+ - lib/spira/type.rb
238
+ - lib/spira/persistence.rb
239
+ - lib/rdf/ext/uri.rb
240
+ homepage: http://ruby-rdf.github.io/spira/
251
241
  licenses:
252
242
  - Public Domain
243
+ metadata: {}
253
244
  post_install_message:
254
245
  rdoc_options: []
255
246
  require_paths:
256
247
  - lib
257
248
  required_ruby_version: !ruby/object:Gem::Requirement
258
- none: false
259
249
  requirements:
260
250
  - - ! '>='
261
251
  - !ruby/object:Gem::Version
262
252
  version: 1.9.2
263
253
  required_rubygems_version: !ruby/object:Gem::Requirement
264
- none: false
265
254
  requirements:
266
255
  - - ! '>='
267
256
  - !ruby/object:Gem::Version
268
257
  version: '0'
269
258
  requirements: []
270
259
  rubyforge_project: spira
271
- rubygems_version: 1.8.25
260
+ rubygems_version: 2.1.11
272
261
  signing_key:
273
- specification_version: 3
262
+ specification_version: 4
274
263
  summary: A framework for using the information in RDF.rb repositories as model objects.
275
264
  test_files: []
276
265
  has_rdoc: yard