fedora_lens 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af9796406a65d286343ded62b45876a28f2c542f
4
+ data.tar.gz: c1237758ac4f5fc1131f9add45cbddf5d657c840
5
+ SHA512:
6
+ metadata.gz: 5bfca9e2b65760e3674ceb986153df14f6de8885c320287cd2367ade51aa1ca78cb0d97a824b479871df63e298442b4b49d590c6469b539984a00704cd440d2e
7
+ data.tar.gz: 9b4fe962ae9a7dc2e70fc9533129b2247e10acd14554247b3ebcdfa25c051f6620f779eadab9f4a3e7c1d4455af4e92c9c57e7e5cd989bf117102d805e3cfbfe
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle
2
+ /fedora/*.war
3
+ /fcrepo4-data/
4
+ Gemfile.lock
5
+ tags
6
+ jetty
7
+ tmp
8
+ pkg
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p353
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ notifications:
2
+ email: false
3
+
4
+ rvm:
5
+ - 2.1.0
6
+
7
+ env:
8
+ global:
9
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
10
+
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem "ldp", github: 'cbeer/ldp'
6
+ gem 'jettywrapper'
7
+
8
+ group :development, :test do
9
+ gem 'byebug' unless ENV['TRAVIS']
10
+ end
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ ## Usage
2
+
3
+ Download and extract Fedora 4:
4
+ ```bash
5
+ rake jetty:download
6
+ rake jetty:unzip
7
+ ```
8
+
9
+ Start Fedora:
10
+ ```bash
11
+ rake jetty:start
12
+ ```
13
+
14
+ ```ruby
15
+ # bundle console
16
+ require 'test_class'
17
+ b = TestClass.new(title: "New resource")
18
+ b.uri
19
+ b.save
20
+ b.id
21
+ a = TestClass.find(b.id)
22
+ a.attributes
23
+ a.primary_id = "some id"
24
+ a.save
25
+ b.reload
26
+ b.attributes
27
+ c = TestClass.create(title: "created resource")
28
+ c.id
29
+ ```
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ ZIP_URL = "https://github.com/projecthydra/hydra-jetty/archive/fedora-4a4.zip"
9
+ require 'jettywrapper'
10
+
11
+ task default: :ci
12
+
13
+ task ci: 'jetty:unzip' do
14
+ jetty_params = Jettywrapper.load_config('test')
15
+ error = Jettywrapper.wrap(jetty_params) do
16
+ Rake::Task[:spec].invoke
17
+ end
18
+ raise "test failures: #{error}" if error
19
+ end
data/config/jetty.yml ADDED
@@ -0,0 +1,6 @@
1
+ default:
2
+ jetty_port: <%= ENV['TEST_JETTY_PORT'] || 8983 %>
3
+ startup_wait: 90
4
+ java_opts:
5
+ - "-Xmx256m"
6
+ - "-XX:MaxPermSize=128m"
data/demo.rb ADDED
@@ -0,0 +1,76 @@
1
+ require 'fedora_lens'
2
+ require 'active_support/core_ext/string'
3
+
4
+ module GenericFileRdfDatastream
5
+ def self.mappings
6
+ {
7
+ part_of: [RDF::DC.isPartOf],
8
+ resource_type: [RDF::DC.type],
9
+ part_of: [RDF::DC.isPartOf],
10
+ resource_type: [RDF::DC.type],
11
+ title: [RDF::DC.title],
12
+ creator: [RDF::DC.creator],
13
+ contributor: [RDF::DC.contributor],
14
+ description: [RDF::DC.description],
15
+ tag: [RDF::DC.relation],
16
+ rights: [RDF::DC.rights],
17
+ publisher: [RDF::DC.publisher],
18
+ date_created: [RDF::DC.created],
19
+ date_uploaded: [RDF::DC.dateSubmitted],
20
+ date_modified: [RDF::DC.modified],
21
+ subject: [RDF::DC.subject],
22
+ language: [RDF::DC.language],
23
+ identifier: [RDF::DC.identifier],
24
+ based_near: [RDF::FOAF.based_near],
25
+ related_url: [RDF::RDFS.seeAlso],
26
+ }
27
+ end
28
+ end
29
+
30
+ module Metadata
31
+ extend ActiveSupport::Concern
32
+
33
+ included do
34
+ # has_metadata "descMetadata", type: GenericFileRdfDatastream
35
+ # has_metadata "properties", type: PropertiesDatastream
36
+ # has_file_datastream "content", type: FileContentDatastream
37
+ # has_file_datastream "thumbnail"
38
+
39
+ # has_attributes :relative_path, :depositor, :import_url, datastream: :properties, multiple: false
40
+ has_attributes :date_uploaded, :date_modified, datastream: :descMetadata, multiple: false
41
+ has_attributes :related_url, :based_near, :part_of, :creator,
42
+ :contributor, :title, :tag, :description, :rights,
43
+ :publisher, :date_created, :subject,
44
+ :resource_type, :identifier, :language, datastream: :descMetadata, multiple: true
45
+ end
46
+
47
+ def descMetadata
48
+ {path: [RDF::URI.new('http://digitalcurationexperts.com/example#descMetadata'),
49
+ FedoraLens::Lenses.single,
50
+ FedoraLens::Lenses.load_or_build_orm],
51
+ type: GenericFileRdfDatastream}
52
+ end
53
+ def properties
54
+ {path: [RDF::URI.new('http://digitalcurationexperts.com/example#properties'),
55
+ FedoraLens::Lenses.single,
56
+ FedoraLens::Lenses.load_or_build_orm],
57
+ type: PropertiesDatastream}
58
+ end
59
+ def has_attributes(*attributes)
60
+ opts = attributes.pop
61
+ attributes.each do |name|
62
+ path = opts[:datastream][:path] + opts[:datastream][:type].mappings[name]
63
+ path << FedoraLens::Lenses.single unless opts[:multiple]
64
+ attribute name, path
65
+ end
66
+ end
67
+ end
68
+
69
+ class Example
70
+ include FedoraLens
71
+ include FedoraLens::Lenses
72
+ extend Metadata
73
+ has_attributes :date_uploaded, datastream: descMetadata, multiple: true
74
+ has_attributes :title, datastream: descMetadata, multiple: true
75
+ # has_attributes :relative_path, datastream: properties, multiple: false
76
+ end
data/fedora/.gitkeep ADDED
File without changes
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fedora_lens/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fedora_lens"
8
+ spec.version = FedoraLens::VERSION
9
+ spec.authors = ["Justin Coyne", "Brian Maddy"]
10
+ spec.email = ["justin@curationexperts.com"]
11
+ spec.summary = %q{A client for Fedora Commons Repository (fcrepo) version 4}
12
+ spec.description = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "APACHE2"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "childprocess"
25
+
26
+ spec.add_dependency 'rdf-turtle', '~> 1.1.2'
27
+ spec.add_dependency 'activemodel', '>= 4.0.2', "< 5.0"
28
+ spec.add_dependency 'nokogiri', '~> 1.6.1'
29
+ spec.add_dependency 'ldp'
30
+ end
@@ -0,0 +1,7 @@
1
+ module FedoraLens
2
+ # generic exception class
3
+ class FedoraLensError < StandardError; end
4
+ # raised when a resource can't be saved
5
+ class RecordNotSaved < FedoraLensError; end
6
+ class AttributeNotSupportedError < FedoraLensError; end
7
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_support/core_ext/hash'
2
+
3
+ module FedoraLens
4
+ class Lens < ActiveSupport::HashWithIndifferentAccess
5
+ def get(source)
6
+ self[:get].call(source)
7
+ end
8
+ def put(source, value)
9
+ self[:put].call(source, value)
10
+ end
11
+ def create(value)
12
+ self[:create].call(value)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ module FedoraLens
2
+ module LensTests
3
+ # See page 6 of the manual for the Harmony language for a description
4
+ # on how lenses work
5
+ # http://www.seas.upenn.edu/~harmony/manual.pdf
6
+ # @example testing a lens that converts xml to a dom and back
7
+ # test_lens(lens, Nokogiri::XML("<a/>"), Nokogiri::XML("<b/>") do |v|
8
+ # v.to_xml
9
+ # end
10
+ # @param [lens]
11
+ # the lens to test
12
+ # @param [value]
13
+ # the value to test with (when calling put)
14
+ # @param [source]
15
+ # the source document this lens operates on
16
+ # @yield [converter]
17
+ # a block that converts the value from the lens to something that can be
18
+ # compared with #== (defaults to the identity function)
19
+ # @yieldparam [value or source]
20
+ # a value that will be compared
21
+ def test_lens(lens, source, value, &block)
22
+ test_lens_get_put(lens, source, &block)
23
+ test_lens_put_get(lens, source, value, &block)
24
+ test_lens_create_get(lens, value, &block)
25
+ end
26
+
27
+ def test_lens_get_put(lens, source)
28
+ it "is well-behaved (GetPut: put(source, get(source)) == source)" do
29
+ converted = lens.put(source, lens.get(source))
30
+ if block_given?
31
+ yield(converted).should eq yield(source)
32
+ else
33
+ converted.should eq source
34
+ end
35
+ end
36
+ end
37
+
38
+ def test_lens_put_get(lens, source, value)
39
+ it "is well-behaved (PutGet: get(put(source, value)) == value)" do
40
+ converted = lens.get(lens.put(source, value))
41
+ if block_given?
42
+ yield(converted).should eq yield(value)
43
+ else
44
+ converted.should eq value
45
+ end
46
+ end
47
+ end
48
+
49
+ def test_lens_create_get(lens, value)
50
+ it "is well-behaved (CreateGet: get(create(value)) == value)" do
51
+ created = lens.get(lens.create(value))
52
+ if block_given?
53
+ yield(created).should eq yield(value)
54
+ else
55
+ created.should eq value
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,149 @@
1
+ require 'fedora_lens/lens'
2
+
3
+ module FedoraLens
4
+ module Lenses
5
+ # We would like to use lenses like this: Lenses.at_css.get(...)
6
+ # Using a simple hash is gross because calls are like this: Lenses.at_css[:get].call(...)
7
+ # If we use a Module, we can't pass in parameters to build a more specific lens like
8
+ # in the case of the at_css lens.
9
+ # If we use a class, we need to call it like this: Lenses::AtCss.new('path').get(...)
10
+ # that's a lot of ".new" that just becomes line noise
11
+ # Classes don't seem to close over their environment as a function would (not sure why...)
12
+ # so we can create anonymous classes with functions
13
+ # Instead, we're just adding the helper functions to a simple hash.
14
+
15
+ class << self
16
+ def single
17
+ Lens[
18
+ get: :first.to_proc,
19
+ put: lambda {|source, value| source[0] = value; source},
20
+ create: lambda {|value| [value]}
21
+ ]
22
+ end
23
+
24
+ def literal_to_string
25
+ Lens[
26
+ get: :to_s.to_proc,
27
+ put: lambda do |source, value|
28
+ if source.is_a?(RDF::Literal)
29
+ RDF::Literal.new(value, language: source.language, datatype: source.datatype)
30
+ else
31
+ RDF::Literal.new(value)
32
+ end
33
+ end
34
+ ]
35
+ end
36
+
37
+ def hash_update
38
+ Lens[
39
+ get: lambda {|hash| hash[key]},
40
+ put: lambda {|hash, pair| hash.merge(pair[0] => pair[1])}
41
+ ]
42
+ end
43
+
44
+ def orm_to_hash(name_to_lens)
45
+ Lens[
46
+ get: lambda do |orm|
47
+ name_to_lens.reduce({}) do |hash, pair|
48
+ key, lens = pair
49
+ hash.merge(key => lens.get(orm))
50
+ end
51
+ end,
52
+ put: lambda do |orm, hash|
53
+ name_to_lens.each do |pair|
54
+ key, lens = pair
55
+ lens.put(orm, hash[key])
56
+ end
57
+ orm
58
+ end
59
+ ]
60
+ end
61
+
62
+ def as_dom
63
+ Lens[
64
+ # TODO figure out a memoizing strategy so we don't parse multiple times
65
+ get: lambda {|xml| Nokogiri::XML(xml)},
66
+ put: lambda {|xml, value| value.to_xml},
67
+ create: lambda {|value| value.to_xml}
68
+ ]
69
+ end
70
+
71
+ def at_css(selector)
72
+ Lens[
73
+ get: lambda {|doc| doc.at_css(selector).content},
74
+ put: lambda {|doc, value|
75
+ doc.at_css(selector).content = value; doc},
76
+ # can't do a css create because we don't know the structure
77
+ ]
78
+ end
79
+
80
+ def get_predicate(predicate)
81
+ Lens[
82
+ get: lambda do |orm|
83
+ orm.value(predicate)
84
+ end,
85
+ put: lambda do |orm, values|
86
+ orm.graph.delete([orm.resource.subject_uri, predicate, nil])
87
+ (values || []).each do |value|
88
+ orm.graph.insert([orm.resource.subject_uri, predicate, value])
89
+ end
90
+ orm
91
+ end,
92
+ create: lambda do |values|
93
+ orm = Ldp::Orm.new(Ldp::Resource.new(nil, '', RDF::Graph.new))
94
+ values.each do |value|
95
+ orm.graph.insert([orm.resource.subject_uri, predicate, value])
96
+ end
97
+ orm
98
+ end
99
+ ]
100
+ end
101
+
102
+ def load_model(klass)
103
+ Lens[
104
+ get: lambda do |id|
105
+ klass.find(id)
106
+ end,
107
+ put: lambda do |id, model|
108
+ model.save
109
+ id
110
+ end
111
+ ]
112
+ end
113
+
114
+ def load_or_build_orm
115
+ Lens[
116
+ get: lambda do |uri|
117
+ if uri.present?
118
+ Ldp::Orm.new(Ldp::Resource.new(FedoraLens.connection, uri.to_s))
119
+ else
120
+ Ldp::Orm.new(Ldp::Resource.new(FedoraLens.connection, nil, RDF::Graph.new))
121
+ end
122
+ end,
123
+ put: lambda do |uri, orm|
124
+ if orm.resource.subject.present?
125
+ orm.save
126
+ else
127
+ orm.resource.create
128
+ end
129
+ orm.resource.subject_uri
130
+ end
131
+ ]
132
+ end
133
+
134
+ def compose(outer, inner)
135
+ Lens[
136
+ get: lambda do |source|
137
+ inner.get(outer.get(source))
138
+ end,
139
+ put: lambda do |source, value|
140
+ outer.put(source, inner.put(outer.get(source), value))
141
+ end
142
+ ]
143
+ end
144
+
145
+ def zip(first, second)
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,3 @@
1
+ module FedoraLens
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,181 @@
1
+ require 'rdf'
2
+ require 'ldp'
3
+ require 'ldp_monkeypatch'
4
+ require 'rdf/turtle'
5
+ require 'nokogiri'
6
+ require 'active_model'
7
+ require 'active_support/concern'
8
+ require 'active_support/core_ext/object'
9
+ require 'active_support/core_ext/class/attribute'
10
+ require 'active_support/core_ext/module/attribute_accessors'
11
+ require 'active_support/core_ext/hash'
12
+ require 'fedora_lens/errors'
13
+
14
+ module FedoraLens
15
+ extend ActiveSupport::Concern
16
+ HOST = "http://localhost:8983/fedora"
17
+ #HOST = "http://localhost:8080"
18
+ PATH = '/rest'
19
+
20
+ def self.connection
21
+ @@connection ||= Ldp::Client.new(HOST)
22
+ end
23
+
24
+ included do
25
+ extend ActiveModel::Naming
26
+ include ActiveModel::Validations
27
+ include ActiveModel::Conversion
28
+
29
+ class_attribute :attributes_as_lenses
30
+ self.attributes_as_lenses = {}.with_indifferent_access
31
+
32
+ attr_reader :attributes
33
+ attr_reader :orm
34
+ end
35
+
36
+ def initialize(subject_or_data = {}, data = nil)
37
+ init_core(subject_or_data, data)
38
+ end
39
+
40
+ def persisted?() false end
41
+
42
+ def errors
43
+ obj = Object.new
44
+ def obj.[](key) [] end
45
+ def obj.full_messages() [] end
46
+ obj
47
+ end
48
+
49
+ def read_attribute_for_validation(key)
50
+ @attributes[key]
51
+ end
52
+
53
+ def reload
54
+ @orm = @orm.reload
55
+ @attributes = get_attributes_from_orm(@orm)
56
+ end
57
+
58
+ def delete
59
+ @orm.resource.delete
60
+ end
61
+
62
+ def save
63
+ @orm = self.class.orm_to_hash.put(@orm, @attributes)
64
+ new_record? ? create_record : update_record
65
+ end
66
+
67
+ def save!
68
+ save || raise(RecordNotSaved)
69
+ end
70
+
71
+ def new_record?
72
+ @new_record
73
+ end
74
+
75
+ def uri
76
+ @orm.try(:resource).try(:subject_uri).try(:to_s)
77
+ end
78
+
79
+ def id
80
+ URI.parse(uri).to_s.sub(HOST + PATH, '') if uri.present?
81
+ end
82
+
83
+ protected
84
+ # This allows you to overide the initializer, but still use this behavior
85
+ def init_core(subject_or_data = {}, data = nil)
86
+ @new_record = true
87
+ case subject_or_data
88
+ when Ldp::Resource
89
+ @orm = Ldp::Orm.new(subject_or_data)
90
+ @attributes = get_attributes_from_orm(@orm)
91
+ when NilClass, Hash
92
+ data = subject_or_data || {}
93
+ @orm = Ldp::Orm.new(Ldp::Resource.new(FedoraLens.connection, nil, RDF::Graph.new))
94
+ @attributes = data.with_indifferent_access
95
+ when String
96
+ data ||= {}
97
+ @orm = Ldp::Orm.new(Ldp::Resource.new(FedoraLens.connection, subject_or_data, RDF::Graph.new))
98
+ @attributes = data.with_indifferent_access
99
+ else
100
+ raise ArgumentError, "#{data.class} is not acceptable"
101
+ end
102
+ end
103
+
104
+ def create_record
105
+ orm.resource.create
106
+ @new_record = false
107
+ true
108
+ end
109
+
110
+ def update_record
111
+ # Fedora errors out when you try to set the rdf:type
112
+ # see https://github.com/cbeer/ldp/issues/2
113
+ orm.graph.delete([@orm.resource.subject_uri,
114
+ RDF::URI.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
115
+ nil])
116
+ orm.save
117
+ orm.last_response.success?
118
+ end
119
+
120
+
121
+ private
122
+
123
+ def get_attributes_from_orm(orm)
124
+ self.class.orm_to_hash.get(orm).with_indifferent_access
125
+ end
126
+
127
+ module ClassMethods
128
+ def find(id)
129
+ resource = Ldp::Resource.new(FedoraLens.connection, id_to_uri(id))
130
+ self.new(resource)
131
+ end
132
+
133
+ def id_to_uri(id)
134
+ "#{HOST}#{PATH}#{id}"
135
+ end
136
+
137
+ def attribute(name, path, options={})
138
+ raise AttributeNotSupportedException if name.to_sym == :id
139
+ attributes_as_lenses[name] = path.map{|s| coerce_to_lens(s)}
140
+ define_method name do
141
+ @attributes[name]
142
+ end
143
+ define_method "#{name}=" do |value|
144
+ @attributes[name] = value
145
+ end
146
+ orm_to_hash = nil # force us to rebuild the aggregate_lens in case it was already built.
147
+ end
148
+
149
+ def create(data)
150
+ model = self.new(data)
151
+ model.save
152
+ model
153
+ end
154
+
155
+ def orm_to_hash
156
+ if @orm_to_hash.nil?
157
+ aggregate_lens = attributes_as_lenses.reduce({}) do |acc, pair|
158
+ name, path = pair
159
+ lens = path.reduce {|outer, inner| Lenses.compose(outer, inner)}
160
+ acc.merge(name => lens)
161
+ end
162
+ @orm_to_hash = Lenses.orm_to_hash(aggregate_lens)
163
+ end
164
+ @orm_to_hash
165
+ end
166
+
167
+ def coerce_to_lens(path_segment)
168
+ if path_segment.is_a? RDF::URI
169
+ Lenses.get_predicate(path_segment)
170
+ else
171
+ path_segment
172
+ end
173
+ end
174
+
175
+ # def has_one(name, scope = nil, options = {})
176
+ # ActiveRecord::Associations::Builder::HasOne.build(self, name, scope, options)
177
+ # end
178
+ end
179
+ end
180
+
181
+ require 'fedora_lens/lenses'
@@ -0,0 +1,22 @@
1
+ require 'ldp'
2
+ module Ldp
3
+
4
+ class Resource
5
+ def create
6
+ # create seems to not be working in ldp, but it's not entirely clear how it should work
7
+ # for example, :new? calls :get, which will raise an error when an object doesn't exist,
8
+ # this means it is impossible to create anything.
9
+ # raise "" if new?
10
+ # puts "MONKEY patch create #{client.inspect}"
11
+ # puts "Graph #{graph.dump(:ttl)}"
12
+ resp = client.post '/fedora/rest', graph.dump(:ttl) do |req|
13
+ # req.headers['Slug'] = subject
14
+ end
15
+
16
+ # puts "Heards #{resp.headers.inspect}"
17
+ @subject = resp.headers['Location']
18
+ # puts "Loc #{@subject.inspect}"
19
+ @subject_uri = nil
20
+ end
21
+ end
22
+ end
data/lib/test_class.rb ADDED
@@ -0,0 +1,64 @@
1
+ require 'fedora_lens'
2
+ class TestClass
3
+ include FedoraLens
4
+ include FedoraLens::Lenses
5
+
6
+ def self.custom_lens(type)
7
+ Lens[
8
+ get: lambda do |doc|
9
+ if node = doc.at_css("relationship[type=#{type}]")
10
+ node.content
11
+ else
12
+ ""
13
+ end
14
+ end,
15
+ put: lambda do |doc, value|
16
+ # TODO: create missing nodes
17
+ # doc.at_css(selector).content = value; doc
18
+ doc << Nokogiri::XML::Node.new("relationships", doc) if doc.root.nil?
19
+ root = doc.root
20
+ relationship = root.at_css("relationship[type=#{type}]")
21
+ if relationship.nil?
22
+ relationship = Nokogiri::XML::Node.new("relationship", doc)
23
+ relationship.set_attribute("type", type)
24
+ root << relationship
25
+ end
26
+ relationship.content = value
27
+ doc
28
+ end,
29
+ create: lambda do |value|
30
+ Nokogiri::XML("<relationships>
31
+ <relationship type=\"#{type}\">#{value}</relationship>
32
+ </relationships>")
33
+ end
34
+ ]
35
+ end
36
+
37
+ attribute :title, [RDF::DC11.title, Lenses.single, Lenses.literal_to_string]
38
+ attribute :mixinTypes, [
39
+ RDF::URI.new("http://fedora.info/definitions/v4/repository#mixinTypes")]
40
+ attribute :primaryType, [
41
+ RDF::URI.new("http://fedora.info/definitions/v4/repository#primaryType"),
42
+ Lenses.single,
43
+ Lenses.literal_to_string]
44
+ attribute :primary_id, [
45
+ RDF::DC11.relation,
46
+ Lenses.single,
47
+ Lenses.literal_to_string,
48
+ Lenses.as_dom,
49
+ # Lenses.at_css("relationship[type=primary]")]
50
+ custom_lens("primary")]
51
+ attribute :secondary, [
52
+ RDF::DC11.relation,
53
+ Lenses.single,
54
+ Lenses.literal_to_string,
55
+ Lenses.as_dom,
56
+ custom_lens("secondary"),
57
+ # Lenses.at_css("relationship[type=secondary]"),
58
+ # Lenses.load_model(TestRelated)
59
+ ]
60
+ # def self.generated_feature_methods
61
+ # end
62
+ # has_one :primary
63
+ end
64
+
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+ require 'fedora_lens/lens_tests'
3
+
4
+ module FedoraLens
5
+ describe Lenses do
6
+ extend LensTests
7
+
8
+ describe ".single" do
9
+ it "gets the first item" do
10
+ Lenses.single.get([:first, :second]).should eq :first
11
+ end
12
+ it "sets the first item" do
13
+ Lenses.single.put([:first, :second], :changed).should eq [:changed, :second]
14
+ end
15
+ it "creates an item in an array" do
16
+ Lenses.single.create(:value).should eq [:value]
17
+ end
18
+ test_lens Lenses.single, [], :foo
19
+ test_lens Lenses.single, [:one], :foo
20
+ test_lens Lenses.single, [:one, :two], :foo
21
+ end
22
+
23
+ describe ".as_dom" do
24
+ it "converts xml to a Nokogiri::XML::Document" do
25
+ xml = "<foo><bar>content</bar></foo>"
26
+ Lenses.as_dom.get(xml).to_xml.should eq Nokogiri::XML(xml).to_xml
27
+ end
28
+ it "converts a modified Nokogiri::XML::Document back to xml" do
29
+ xml = "<foo><bar>content</bar></foo>"
30
+ modified = Nokogiri::XML("<foo><bar>changed</bar></foo>")
31
+ Lenses.as_dom.put(xml, modified.dup).should eq modified.to_xml
32
+ end
33
+ it "creates a new string of xml" do
34
+ value = Nokogiri::XML("<foo><bar>created</bar></foo>")
35
+ Lenses.as_dom.create(value).should eq value.to_xml
36
+ end
37
+ test_lens(Lenses.as_dom,
38
+ Nokogiri::XML("<foo><bar>content</bar></foo>").to_xml,
39
+ Nokogiri::XML("<foo><bar>new content</bar></foo>")){|v| v.to_s}
40
+ end
41
+
42
+ describe ".at_css" do
43
+ it "gets the content at the css selector" do
44
+ dom = Nokogiri::XML("<foo><bar>content</bar></foo>")
45
+ Lenses.at_css('foo bar').get(dom).should eq 'content'
46
+ end
47
+ it "sets the first item" do
48
+ dom = Nokogiri::XML("<foo><bar>content</bar></foo>")
49
+ expected = Nokogiri::XML("<foo><bar>changed</bar></foo>")
50
+ Lenses.at_css('foo bar').put(dom, :changed).to_xml.should eq expected.to_xml
51
+ end
52
+ test_lens_get_put(Lenses.at_css("foo bar"), Nokogiri::XML("<foo><bar>content</bar></foo>"))
53
+ test_lens_put_get(Lenses.at_css("foo bar"),
54
+ Nokogiri::XML("<foo><bar>content</bar></foo>"),
55
+ "new content")
56
+ end
57
+
58
+ describe ".get_predicate" do
59
+ let(:orm) do
60
+ graph = RDF::Graph.new
61
+ orm = Ldp::Orm.new(Ldp::Resource.new(nil, '', graph))
62
+ orm.graph.insert([orm.resource.subject_uri, RDF::DC11.title, "title"])
63
+ orm
64
+ end
65
+ it "converts an Ldp::Orm to the value of the specified predicate" do
66
+ Lenses.get_predicate(RDF::DC11.title).get(orm).first.should eq RDF::Literal.new("title")
67
+ end
68
+ it "sets the value of an Ldp::Orm for the specified predicate" do
69
+ Lenses.get_predicate(RDF::DC11.title).put(orm, [RDF::Literal.new("new")]).value(RDF::DC11.title).first.should eq RDF::Literal.new("new")
70
+ end
71
+ it "creates a new Ldp::Orm with the value for a specified predicate" do
72
+ converted = Lenses.get_predicate(RDF::DC11.title).create([RDF::Literal.new("title")])
73
+ converted.graph.dump(:ttl).should eq orm.graph.dump(:ttl)
74
+ end
75
+ graph = RDF::Graph.new
76
+ orm = Ldp::Orm.new(Ldp::Resource.new(nil, '', graph))
77
+ orm.graph.insert([orm.resource.subject_uri, RDF::DC11.title, "title"])
78
+ test_lens(Lenses.get_predicate(RDF::DC11.title), orm, [RDF::Literal.new("new title")]) do |v|
79
+ if v.is_a? Ldp::Orm
80
+ v.value(RDF::DC11.title)
81
+ else
82
+ v
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ describe FedoraLens do
4
+ include ActiveModel::Lint::Tests
5
+
6
+ class TestClass
7
+ include FedoraLens
8
+ attribute :title, [RDF::DC11.title, Lenses.single, Lenses.literal_to_string]
9
+ # attribute :xml_title, [RDF::DC11.title, Lenses.single]
10
+ end
11
+
12
+ # for ActiveModel::Lint::Tests
13
+ def setup
14
+ @model = TestClass.new
15
+ end
16
+
17
+ subject { TestClass.new }
18
+
19
+ describe ".find" do
20
+ context "when the object doesn't exist" do
21
+ it "should raise an error" do
22
+ expect{ TestClass.find('bahvejlavawwv') }.to raise_error Ldp::NotFound
23
+ end
24
+ end
25
+
26
+ context "when the object exists" do
27
+ let(:existing) { TestClass.create(title: "created resource") }
28
+ subject { TestClass.find(existing.id) }
29
+ it { should be_kind_of TestClass }
30
+ its(:id) { should eq existing.id }
31
+ end
32
+ end
33
+
34
+ describe ".delete" do
35
+ subject { TestClass.create(title: "created resource") }
36
+
37
+ it "should be deleted" do
38
+ subject.delete
39
+ expect{ TestClass.find(subject.id) }.to raise_error Ldp::NotFound
40
+ end
41
+ end
42
+
43
+ describe ".create" do
44
+ subject { TestClass.create(attributes) }
45
+ context "with a hash" do
46
+ let(:attributes) { { title: "created resource" } }
47
+ it "creates a resource" do
48
+ expect(TestClass.find(subject.id).title).to eq "created resource"
49
+ end
50
+ end
51
+ context "with nil" do
52
+ let(:attributes) { nil }
53
+ it "creates a resource" do
54
+ expect(TestClass.find(subject.id)).to be_kind_of TestClass
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#id" do
60
+ it "should not have 'fedora' in the id" do
61
+ m = TestClass.new('http://localhost:8983/fedora/rest/41/0d/6b/47/410d6b47-ce9c-4fa0-91e2-d62765667c52')
62
+ expect(m.id).to eq '/41/0d/6b/47/410d6b47-ce9c-4fa0-91e2-d62765667c52'
63
+ end
64
+ end
65
+
66
+
67
+ describe ".save" do
68
+ it "saves a new resource" do
69
+ m = TestClass.new(title: "created resource")
70
+ m.save
71
+ TestClass.find(m.id).title.should eq "created resource"
72
+ end
73
+
74
+ it "saves an updated resource" do
75
+ m = TestClass.create(title: "created resource")
76
+ m.reload
77
+ m.title = "changed title"
78
+ m.save
79
+ TestClass.find(m.id).title.should eq "changed title"
80
+ end
81
+
82
+ context "with a supplied id" do
83
+ subject { TestClass.new(TestClass.id_to_uri('foobar')) }
84
+
85
+ it "saves with that id" do
86
+ expect(subject.new_record?).to be_true
87
+ expect(subject.save).to be_true
88
+ expect(subject.new_record?).to be_false
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ describe ".attribute" do
96
+ it "makes a setter/getter" do
97
+ subject.title = "foo"
98
+ subject.title.should eq "foo"
99
+ end
100
+
101
+ it "loads from rdf" do
102
+ end
103
+
104
+ it "mixes rdf and xml" do
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,16 @@
1
+ require 'bundler'
2
+ require "bundler/setup"
3
+ require 'fedora_lens'
4
+ require 'fedora_lens/lenses'
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+
11
+ # Run specs in random order to surface order dependencies. If you find an
12
+ # order dependency and want to debug it, you can fix the order by providing
13
+ # the seed, which is printed after each run.
14
+ # --seed 1234
15
+ config.order = 'random'
16
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fedora_lens
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Justin Coyne
8
+ - Brian Maddy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.5'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '1.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: childprocess
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rdf-turtle
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.1.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: 1.1.2
84
+ - !ruby/object:Gem::Dependency
85
+ name: activemodel
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: 4.0.2
91
+ - - <
92
+ - !ruby/object:Gem::Version
93
+ version: '5.0'
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: 4.0.2
101
+ - - <
102
+ - !ruby/object:Gem::Version
103
+ version: '5.0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: nokogiri
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 1.6.1
111
+ type: :runtime
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 1.6.1
118
+ - !ruby/object:Gem::Dependency
119
+ name: ldp
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ type: :runtime
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ description: ''
133
+ email:
134
+ - justin@curationexperts.com
135
+ executables: []
136
+ extensions: []
137
+ extra_rdoc_files: []
138
+ files:
139
+ - .gitignore
140
+ - .rspec
141
+ - .ruby-version
142
+ - .travis.yml
143
+ - Gemfile
144
+ - README.md
145
+ - Rakefile
146
+ - config/jetty.yml
147
+ - demo.rb
148
+ - fedora/.gitkeep
149
+ - fedora_lens.gemspec
150
+ - lib/fedora_lens.rb
151
+ - lib/fedora_lens/errors.rb
152
+ - lib/fedora_lens/lens.rb
153
+ - lib/fedora_lens/lens_tests.rb
154
+ - lib/fedora_lens/lenses.rb
155
+ - lib/fedora_lens/version.rb
156
+ - lib/ldp_monkeypatch.rb
157
+ - lib/test_class.rb
158
+ - spec/fedora_lens/lenses_spec.rb
159
+ - spec/fedora_lens_spec.rb
160
+ - spec/spec_helper.rb
161
+ homepage: ''
162
+ licenses:
163
+ - APACHE2
164
+ metadata: {}
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - '>='
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 2.1.11
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: A client for Fedora Commons Repository (fcrepo) version 4
185
+ test_files:
186
+ - spec/fedora_lens/lenses_spec.rb
187
+ - spec/fedora_lens_spec.rb
188
+ - spec/spec_helper.rb
189
+ has_rdoc: