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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af9796406a65d286343ded62b45876a28f2c542f
4
- data.tar.gz: c1237758ac4f5fc1131f9add45cbddf5d657c840
3
+ metadata.gz: 16b83b0c8b5f99413f3eec0f08a0b75609f35a7c
4
+ data.tar.gz: dec9a72626b9c00511782586aa8b904f63558380
5
5
  SHA512:
6
- metadata.gz: 5bfca9e2b65760e3674ceb986153df14f6de8885c320287cd2367ade51aa1ca78cb0d97a824b479871df63e298442b4b49d590c6469b539984a00704cd440d2e
7
- data.tar.gz: 9b4fe962ae9a7dc2e70fc9533129b2247e10acd14554247b3ebcdfa25c051f6620f779eadab9f4a3e7c1d4455af4e92c9c57e7e5cd989bf117102d805e3cfbfe
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
@@ -1,3 +1,3 @@
1
1
  module FedoraLens
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -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.should eq "foo"
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.1
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-14 00:00:00.000000000 Z
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