fedora_lens 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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