fedora_lens 0.0.1 → 0.0.2
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 +4 -4
- data/lib/fedora_lens.rb +13 -24
- data/lib/fedora_lens/attribute_methods.rb +143 -0
- data/lib/fedora_lens/attribute_methods/read.rb +61 -0
- data/lib/fedora_lens/attribute_methods/write.rb +50 -0
- data/lib/fedora_lens/version.rb +1 -1
- data/spec/fedora_lens_spec.rb +10 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16b83b0c8b5f99413f3eec0f08a0b75609f35a7c
|
4
|
+
data.tar.gz: dec9a72626b9c00511782586aa8b904f63558380
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07dd2afaa5f9c46f2ecdbeba122c0aee828edf3240f2f52c37c3ecee72ad7ffef3a1a636389bfd6329b6997eb9b53cfcf4dd35681e0f64771a061d2294e25582
|
7
|
+
data.tar.gz: 7c9928a40da331750b368189327bef44f446c82a9ea05ccf50f5be08682bf811e17927e2e2cb2de3d5f67d37265feed71f87231c87f87f2625bce683a40d35c6
|
data/lib/fedora_lens.rb
CHANGED
@@ -13,6 +13,18 @@ require 'fedora_lens/errors'
|
|
13
13
|
|
14
14
|
module FedoraLens
|
15
15
|
extend ActiveSupport::Concern
|
16
|
+
extend ActiveSupport::Autoload
|
17
|
+
autoload :AttributeMethods
|
18
|
+
|
19
|
+
module AttributeMethods
|
20
|
+
extend ActiveSupport::Autoload
|
21
|
+
|
22
|
+
eager_autoload do
|
23
|
+
autoload :Read
|
24
|
+
autoload :Write
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
HOST = "http://localhost:8983/fedora"
|
17
29
|
#HOST = "http://localhost:8080"
|
18
30
|
PATH = '/rest'
|
@@ -25,11 +37,8 @@ module FedoraLens
|
|
25
37
|
extend ActiveModel::Naming
|
26
38
|
include ActiveModel::Validations
|
27
39
|
include ActiveModel::Conversion
|
40
|
+
include FedoraLens::AttributeMethods
|
28
41
|
|
29
|
-
class_attribute :attributes_as_lenses
|
30
|
-
self.attributes_as_lenses = {}.with_indifferent_access
|
31
|
-
|
32
|
-
attr_reader :attributes
|
33
42
|
attr_reader :orm
|
34
43
|
end
|
35
44
|
|
@@ -134,18 +143,6 @@ module FedoraLens
|
|
134
143
|
"#{HOST}#{PATH}#{id}"
|
135
144
|
end
|
136
145
|
|
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
146
|
def create(data)
|
150
147
|
model = self.new(data)
|
151
148
|
model.save
|
@@ -164,14 +161,6 @@ module FedoraLens
|
|
164
161
|
@orm_to_hash
|
165
162
|
end
|
166
163
|
|
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
164
|
# def has_one(name, scope = nil, options = {})
|
176
165
|
# ActiveRecord::Associations::Builder::HasOne.build(self, name, scope, options)
|
177
166
|
# end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'active_support/core_ext/object'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
|
4
|
+
module FedoraLens
|
5
|
+
module AttributeMethods
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include ActiveModel::AttributeMethods
|
8
|
+
|
9
|
+
AttrNames = Module.new {
|
10
|
+
def self.set_name_cache(name, value)
|
11
|
+
const_name = "ATTR_#{name}"
|
12
|
+
unless const_defined? const_name
|
13
|
+
const_set const_name, value.dup.freeze
|
14
|
+
end
|
15
|
+
end
|
16
|
+
}
|
17
|
+
|
18
|
+
class AttributeMethodCache
|
19
|
+
def initialize
|
20
|
+
@module = Module.new
|
21
|
+
@method_cache = ThreadSafe::Cache.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](name)
|
25
|
+
@method_cache.compute_if_absent(name) do
|
26
|
+
safe_name = name.unpack('h*').first
|
27
|
+
temp_method = "__temp__#{safe_name}"
|
28
|
+
FedoraLens::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
29
|
+
@module.module_eval method_body(temp_method, safe_name), __FILE__, __LINE__
|
30
|
+
@module.instance_method temp_method
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def method_body; raise NotImplementedError; end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
included do
|
40
|
+
class_attribute :attributes_as_lenses
|
41
|
+
self.attributes_as_lenses = {}.with_indifferent_access
|
42
|
+
|
43
|
+
initialize_generated_modules
|
44
|
+
include Read
|
45
|
+
include Write
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns an array of names for the attributes available on this object.
|
49
|
+
#
|
50
|
+
# class Person
|
51
|
+
# include FedoraLens
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# person = Person.new
|
55
|
+
# person.attribute_names
|
56
|
+
# # => ["id", "created_at", "updated_at", "name", "age"]
|
57
|
+
def attribute_names
|
58
|
+
@attributes.keys
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
|
62
|
+
#
|
63
|
+
# class Person
|
64
|
+
# include FedoraLens
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# person = Person.create(name: 'Francesco', age: 22)
|
68
|
+
# person.attributes
|
69
|
+
# # => {"id"=>3, "created_at"=>Sun, 21 Oct 2012 04:53:04, "updated_at"=>Sun, 21 Oct 2012 04:53:04, "name"=>"Francesco", "age"=>22}
|
70
|
+
def attributes
|
71
|
+
attribute_names.each_with_object({}) { |name, attrs|
|
72
|
+
attrs[name] = read_attribute(name)
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
|
78
|
+
# "2004-12-12" in a date column is cast to a date object, like Date.new(2004, 12, 12)). It raises
|
79
|
+
# <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing.
|
80
|
+
#
|
81
|
+
# Alias for the <tt>read_attribute</tt> method.
|
82
|
+
#
|
83
|
+
# class Person < ActiveRecord::Base
|
84
|
+
# belongs_to :organization
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# person = Person.new(name: 'Francesco', age: '22')
|
88
|
+
# person[:name] # => "Francesco"
|
89
|
+
# person[:age] # => 22
|
90
|
+
#
|
91
|
+
# person = Person.select('id').first
|
92
|
+
# person[:name] # => ActiveModel::MissingAttributeError: missing attribute: name
|
93
|
+
# person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute: organization_id
|
94
|
+
def [](attr_name)
|
95
|
+
read_attribute(attr_name) { |n| missing_attribute(n, caller) }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
|
99
|
+
# (Alias for the protected <tt>write_attribute</tt> method).
|
100
|
+
#
|
101
|
+
# class Person
|
102
|
+
# include FedoraLens
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# person = Person.new
|
106
|
+
# person[:age] = '22'
|
107
|
+
# person[:age] # => 22
|
108
|
+
# person[:age] # => Fixnum
|
109
|
+
def []=(attr_name, value)
|
110
|
+
write_attribute(attr_name, value)
|
111
|
+
end
|
112
|
+
|
113
|
+
module ClassMethods
|
114
|
+
def initialize_generated_modules # :nodoc:
|
115
|
+
@generated_attribute_methods = Module.new { extend Mutex_m }
|
116
|
+
include @generated_attribute_methods
|
117
|
+
end
|
118
|
+
|
119
|
+
def attribute(name, path, options={})
|
120
|
+
raise AttributeNotSupportedException if name.to_sym == :id
|
121
|
+
attributes_as_lenses[name] = path.map{|s| coerce_to_lens(s)}
|
122
|
+
generate_method(name)
|
123
|
+
orm_to_hash = nil # force us to rebuild the aggregate_lens in case it was already built.
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
def coerce_to_lens(path_segment)
|
128
|
+
if path_segment.is_a? RDF::URI
|
129
|
+
Lenses.get_predicate(path_segment)
|
130
|
+
else
|
131
|
+
path_segment
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param name [Symbol] name of the attribute to generate
|
136
|
+
def generate_method(name)
|
137
|
+
generated_attribute_methods.synchronize do
|
138
|
+
define_attribute_methods name
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module FedoraLens
|
2
|
+
module AttributeMethods
|
3
|
+
module Read
|
4
|
+
ReaderMethodCache = Class.new(AttributeMethodCache) {
|
5
|
+
private
|
6
|
+
# We want to generate the methods via module_eval rather than
|
7
|
+
# define_method, because define_method is slower on dispatch.
|
8
|
+
# Evaluating many similar methods may use more memory as the instruction
|
9
|
+
# sequences are duplicated and cached (in MRI). define_method may
|
10
|
+
# be slower on dispatch, but if you're careful about the closure
|
11
|
+
# created, then define_method will consume much less memory.
|
12
|
+
#
|
13
|
+
# But sometimes the database might return columns with
|
14
|
+
# characters that are not allowed in normal method names (like
|
15
|
+
# 'my_column(omg)'. So to work around this we first define with
|
16
|
+
# the __temp__ identifier, and then use alias method to rename
|
17
|
+
# it to what we want.
|
18
|
+
#
|
19
|
+
# We are also defining a constant to hold the frozen string of
|
20
|
+
# the attribute name. Using a constant means that we do not have
|
21
|
+
# to allocate an object on each call to the attribute method.
|
22
|
+
# Making it frozen means that it doesn't get duped when used to
|
23
|
+
# key the @attributes_cache in read_attribute.
|
24
|
+
def method_body(method_name, const_name)
|
25
|
+
<<-EOMETHOD
|
26
|
+
def #{method_name}
|
27
|
+
name = ::FedoraLens::AttributeMethods::AttrNames::ATTR_#{const_name}
|
28
|
+
read_attribute(name) { |n| missing_attribute(n, caller) }
|
29
|
+
end
|
30
|
+
EOMETHOD
|
31
|
+
end
|
32
|
+
}.new
|
33
|
+
|
34
|
+
extend ActiveSupport::Concern
|
35
|
+
|
36
|
+
# Returns the value of the attribute identified by <tt>attr_name</tt> after
|
37
|
+
# it has been typecast (for example, "2004-12-12" in a date column is cast
|
38
|
+
# to a date object, like Date.new(2004, 12, 12)).
|
39
|
+
def read_attribute(attr_name)
|
40
|
+
name = attr_name.to_s
|
41
|
+
@attributes.fetch(name, nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def attribute(attribute_name)
|
46
|
+
read_attribute(attribute_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
def define_method_attribute(name)
|
52
|
+
method = ReaderMethodCache[name.to_s]
|
53
|
+
generated_attribute_methods.module_eval {
|
54
|
+
define_method name, method
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module FedoraLens
|
2
|
+
module AttributeMethods
|
3
|
+
module Write
|
4
|
+
WriterMethodCache = Class.new(AttributeMethodCache) {
|
5
|
+
private
|
6
|
+
|
7
|
+
def method_body(method_name, const_name)
|
8
|
+
<<-EOMETHOD
|
9
|
+
def #{method_name}(value)
|
10
|
+
name = ::FedoraLens::AttributeMethods::AttrNames::ATTR_#{const_name}
|
11
|
+
write_attribute(name, value)
|
12
|
+
end
|
13
|
+
EOMETHOD
|
14
|
+
end
|
15
|
+
}.new
|
16
|
+
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
attribute_method_suffix "="
|
21
|
+
end
|
22
|
+
|
23
|
+
def write_attribute(attribute_name, value)
|
24
|
+
#column = column_for_attribute(attribute_name)
|
25
|
+
column = true # TODO check that attribute_name is valid
|
26
|
+
|
27
|
+
if column
|
28
|
+
@attributes[attribute_name] = value
|
29
|
+
else
|
30
|
+
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attribute_name}'"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def attribute=(attribute_name, value)
|
36
|
+
write_attribute(attribute_name, value)
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
def define_method_attribute=(name)
|
41
|
+
method = WriterMethodCache[name.to_s]
|
42
|
+
generated_attribute_methods.module_eval {
|
43
|
+
define_method "#{name}=", method
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/fedora_lens/version.rb
CHANGED
data/spec/fedora_lens_spec.rb
CHANGED
@@ -95,7 +95,16 @@ describe FedoraLens do
|
|
95
95
|
describe ".attribute" do
|
96
96
|
it "makes a setter/getter" do
|
97
97
|
subject.title = "foo"
|
98
|
-
subject.title.
|
98
|
+
expect(subject.title).to eq "foo"
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should return nil if it hasn't been set" do
|
102
|
+
expect(subject.title).to be_nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "has a [] setter/getter" do
|
106
|
+
subject[:title] = 'foo'
|
107
|
+
expect(subject[:title]).to eq 'foo'
|
99
108
|
end
|
100
109
|
|
101
110
|
it "loads from rdf" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fedora_lens
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-04-
|
12
|
+
date: 2014-04-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -148,6 +148,9 @@ files:
|
|
148
148
|
- fedora/.gitkeep
|
149
149
|
- fedora_lens.gemspec
|
150
150
|
- lib/fedora_lens.rb
|
151
|
+
- lib/fedora_lens/attribute_methods.rb
|
152
|
+
- lib/fedora_lens/attribute_methods/read.rb
|
153
|
+
- lib/fedora_lens/attribute_methods/write.rb
|
151
154
|
- lib/fedora_lens/errors.rb
|
152
155
|
- lib/fedora_lens/lens.rb
|
153
156
|
- lib/fedora_lens/lens_tests.rb
|