active-fedora 9.10.0.pre1 → 9.10.0.pre2

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: 7df084ee06f2755c8ff2fc057f8b6a8751bd142a
4
- data.tar.gz: 622c46cd850334fe1950625b1e9a5b869f0dd2c0
3
+ metadata.gz: b9fa729bb22950bf6f1a5a8910eef83e17d699b6
4
+ data.tar.gz: 2230ceaf9cf100c0737997c5235c0a87364ec2df
5
5
  SHA512:
6
- metadata.gz: df6c6b7f8af5f3e511434c06b0e667a3234841c4483dac0a7f508cddf89d4e056a087d7ea2186ea0b454133ff8b027e692bd8acf190bd93a4969c7effd874d09
7
- data.tar.gz: 17116f1df54b097ad14272537509d976f3eb9dd9f8911dca31c6ea80ce478af5c398255066628b5620938b5ee3a393a15af58577ac2d7ed3c88bf19e91df47ea
6
+ metadata.gz: df06b4f7448346189c3ca49029200205eaf671a84854035fba131dc60d84f0954aaf79df54e29746118cac1074ca2241e7b5bc7e291f89b120e44340b034d250
7
+ data.tar.gz: 60a819b84ffd5f68bdb80436648621738e2b77b68e629265be3d3257efa566969d33c040660a561445c39a60d38742865afd0dd6b6681ef0aeb7bfc8cd08d961
@@ -43,6 +43,9 @@ Metrics/CyclomaticComplexity:
43
43
  - 'lib/active_fedora/file_configurator.rb'
44
44
  - 'lib/active_fedora/file.rb'
45
45
  - 'lib/active_fedora/datastreams/nokogiri_datastreams.rb'
46
+ - 'lib/active_fedora/attribute_methods.rb'
47
+ - 'lib/active_fedora/scoping/named.rb'
48
+ - 'lib/active_fedora/inheritance.rb'
46
49
 
47
50
  Metrics/PerceivedComplexity:
48
51
  Exclude:
@@ -57,6 +60,9 @@ Metrics/PerceivedComplexity:
57
60
  - 'lib/active_fedora/associations/builder/indirectly_contains.rb'
58
61
  - 'lib/active_fedora/associations/builder/directly_contains_one.rb'
59
62
  - 'lib/active_fedora/associations/collection_association.rb'
63
+ - 'lib/active_fedora/attribute_methods.rb'
64
+ - 'lib/active_fedora/scoping/named.rb'
65
+ - 'lib/active_fedora/inheritance.rb'
60
66
 
61
67
  Metrics/ModuleLength:
62
68
  Exclude:
@@ -103,6 +109,7 @@ Style/AccessorMethodName:
103
109
 
104
110
  Style/PredicateName:
105
111
  Exclude:
112
+ - 'lib/active_fedora/attribute_methods.rb'
106
113
  - 'lib/active_fedora/relation/finder_methods.rb'
107
114
  - 'lib/active_fedora/versionable.rb'
108
115
  - 'lib/active_fedora/reflection.rb'
@@ -40,6 +40,7 @@ module ActiveFedora #:nodoc:
40
40
  autoload :AssociationRelation
41
41
  autoload :Associations
42
42
  autoload :AttachedFiles
43
+ autoload :AttributeAssignment
43
44
  autoload :AttributeMethods
44
45
  autoload :Attributes
45
46
  autoload :AutosaveAssociation
@@ -50,6 +51,7 @@ module ActiveFedora #:nodoc:
50
51
  autoload :Checksum
51
52
  autoload :CleanConnection
52
53
  autoload :Config
54
+ autoload :Common
53
55
  autoload :Core
54
56
  autoload_under 'containers' do
55
57
  autoload :Container
@@ -71,6 +73,7 @@ module ActiveFedora #:nodoc:
71
73
  autoload :File
72
74
  autoload :FileConfigurator
73
75
  autoload :FilePathBuilder
76
+ autoload :FilePersistence
74
77
  autoload :FileRelation
75
78
  autoload :FilesHash
76
79
  autoload :FixityService
@@ -79,6 +82,7 @@ module ActiveFedora #:nodoc:
79
82
  autoload :Indexing
80
83
  autoload :IndexingService
81
84
  autoload :InheritableAccessors
85
+ autoload :Inheritance
82
86
  autoload :InboundRelationConnection
83
87
  autoload :LdpCache
84
88
  autoload :LdpResource
@@ -72,10 +72,10 @@ module ActiveFedora
72
72
  # This method is abstract in the sense that it relies on
73
73
  # +count_records+, which is a method descendants have to provide.
74
74
  def size
75
- if @owner.new_record? && @target
76
- @target.size
77
- elsif !loaded? && @target.is_a?(Array)
78
- unsaved_records = @target.select(&:new_record?)
75
+ if !find_target? || loaded?
76
+ target.size
77
+ elsif !loaded? && target.is_a?(Array)
78
+ unsaved_records = target.select(&:new_record?)
79
79
  unsaved_records.size + count_records
80
80
  else
81
81
  count_records
@@ -212,7 +212,7 @@ module ActiveFedora
212
212
  if attrs.is_a?(Array)
213
213
  attrs.collect { |attr| create(attr) }
214
214
  else
215
- create_record(attrs) do |record|
215
+ _create_record(attrs) do |record|
216
216
  yield(record) if block_given?
217
217
  record.save
218
218
  end
@@ -220,7 +220,7 @@ module ActiveFedora
220
220
  end
221
221
 
222
222
  def create!(attrs = {})
223
- create_record(attrs) do |record|
223
+ _create_record(attrs) do |record|
224
224
  yield(record) if block_given?
225
225
  record.save!
226
226
  end
@@ -340,7 +340,7 @@ module ActiveFedora
340
340
  end
341
341
  end
342
342
 
343
- def create_record(attributes, raise = false)
343
+ def _create_record(attributes, raise = false)
344
344
  attributes.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
345
345
  ensure_owner_is_not_new
346
346
 
@@ -0,0 +1,55 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+
3
+ module ActiveFedora
4
+ module AttributeAssignment
5
+ include ActiveModel::ForbiddenAttributesProtection
6
+
7
+ # Alias for assign_attributes.
8
+ def attributes=(attributes)
9
+ assign_attributes(attributes)
10
+ end
11
+
12
+ # Allows you to set all the attributes by passing in a hash of attributes with
13
+ # keys matching the attribute names.
14
+ #
15
+ # If the passed hash responds to <tt>permitted?</tt> method and the return value
16
+ # of this method is +false+ an <tt>ActiveModel::ForbiddenAttributesError</tt>
17
+ # exception is raised.
18
+ #
19
+ # class Cat
20
+ # include ActiveModel::AttributeAssignment
21
+ # attr_accessor :name, :status
22
+ # end
23
+ #
24
+ # cat = Cat.new
25
+ # cat.assign_attributes(name: "Gorby", status: "yawning")
26
+ # cat.name # => 'Gorby'
27
+ # cat.status => 'yawning'
28
+ # cat.assign_attributes(status: "sleeping")
29
+ # cat.name # => 'Gorby'
30
+ # cat.status => 'sleeping'
31
+ def assign_attributes(new_attributes)
32
+ unless new_attributes.respond_to?(:stringify_keys)
33
+ raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
34
+ end
35
+ return if new_attributes.nil? || new_attributes.empty?
36
+
37
+ attributes = new_attributes.stringify_keys
38
+ _assign_attributes(sanitize_for_mass_assignment(attributes))
39
+ end
40
+
41
+ private
42
+
43
+ def _assign_attributes(attributes)
44
+ attributes.each do |k, v|
45
+ _assign_attribute(k, v)
46
+ end
47
+ end
48
+
49
+ def _assign_attribute(k, v)
50
+ raise UnknownAttributeError.new(self, k) unless respond_to?("#{k}=")
51
+
52
+ public_send("#{k}=", v)
53
+ end
54
+ end
55
+ end
@@ -13,26 +13,97 @@ module ActiveFedora
13
13
  end
14
14
  end
15
15
 
16
- class AttributeMethodCache
17
- def initialize
18
- @module = Module.new
19
- @method_cache = ThreadSafe::Cache.new
16
+ BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass).freeze
17
+
18
+ class GeneratedAttributeMethods < Module; end # :nodoc:
19
+
20
+ module ClassMethods
21
+ def inherited(child_class) #:nodoc:
22
+ child_class.initialize_generated_modules
23
+ super
24
+ end
25
+
26
+ def initialize_generated_modules # :nodoc:
27
+ @generated_attribute_methods = GeneratedAttributeMethods.new { extend Mutex_m }
28
+ @attribute_methods_generated = false
29
+ include @generated_attribute_methods
30
+
31
+ super
32
+ end
33
+
34
+ # Raises an ActiveRecord::DangerousAttributeError exception when an
35
+ # \Active \Record method is defined in the model, otherwise +false+.
36
+ #
37
+ # class Person < ActiveRecord::Base
38
+ # def save
39
+ # 'already defined by Active Record'
40
+ # end
41
+ # end
42
+ #
43
+ # Person.instance_method_already_implemented?(:save)
44
+ # # => ActiveRecord::DangerousAttributeError: save is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.
45
+ #
46
+ # Person.instance_method_already_implemented?(:name)
47
+ # # => false
48
+ def instance_method_already_implemented?(method_name)
49
+ if dangerous_attribute_method?(method_name)
50
+ raise DangerousAttributeError, "#{method_name} is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name."
51
+ end
52
+
53
+ if superclass == Base
54
+ super
55
+ else
56
+ # If ThisClass < ... < SomeSuperClass < ... < Base and SomeSuperClass
57
+ # defines its own attribute method, then we don't want to overwrite that.
58
+ defined = method_defined_within?(method_name, superclass, Base) &&
59
+ !superclass.instance_method(method_name).owner.is_a?(GeneratedAttributeMethods)
60
+ defined || super
61
+ end
62
+ end
63
+
64
+ # A method name is 'dangerous' if it is already (re)defined by Active Fedora, but
65
+ # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
66
+ def dangerous_attribute_method?(name) # :nodoc:
67
+ method_defined_within?(name, Base)
68
+ end
69
+
70
+ def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
71
+ if klass.method_defined?(name) || klass.private_method_defined?(name)
72
+ if superklass.method_defined?(name) || superklass.private_method_defined?(name)
73
+ klass.instance_method(name).owner != superklass.instance_method(name).owner
74
+ else
75
+ true
76
+ end
77
+ else
78
+ false
79
+ end
80
+ end
81
+
82
+ # A class method is 'dangerous' if it is already (re)defined by Active Record, but
83
+ # not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
84
+ def dangerous_class_method?(method_name)
85
+ BLACKLISTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
20
86
  end
21
87
 
22
- def [](name)
23
- @method_cache.compute_if_absent(name) do
24
- safe_name = name.unpack('h*').first
25
- temp_method = "__temp__#{safe_name}"
26
- ActiveFedora::AttributeMethods::AttrNames.set_name_cache safe_name, name
27
- @module.module_eval method_body(temp_method, safe_name), __FILE__, __LINE__
28
- @module.instance_method temp_method
88
+ def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
89
+ if klass.respond_to?(name, true)
90
+ if superklass.respond_to?(name, true)
91
+ klass.method(name).owner != superklass.method(name).owner
92
+ else
93
+ true
94
+ end
95
+ else
96
+ false
29
97
  end
30
98
  end
31
99
 
32
100
  private
33
101
 
34
- def method_body
35
- raise NotImplementedError
102
+ # @param name [Symbol] name of the attribute to generate
103
+ def generate_method(name)
104
+ generated_attribute_methods.synchronize do
105
+ define_attribute_methods name
106
+ end
36
107
  end
37
108
  end
38
109
 
@@ -43,6 +114,19 @@ module ActiveFedora
43
114
  include Dirty
44
115
  end
45
116
 
117
+ # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
118
+ #
119
+ # class Person < ActiveRecord::Base
120
+ # end
121
+ #
122
+ # person = Person.new
123
+ # person.has_attribute?(:name) # => true
124
+ # person.has_attribute?('age') # => true
125
+ # person.has_attribute?(:nothing) # => false
126
+ def has_attribute?(attr_name)
127
+ attribute_names.include?(attr_name.to_s)
128
+ end
129
+
46
130
  # Returns an array of names for the attributes available on this object.
47
131
  #
48
132
  # class Person < ActiveFedora::Base
@@ -69,6 +153,58 @@ module ActiveFedora
69
153
  end
70
154
  end
71
155
 
156
+ # Returns an <tt>#inspect</tt>-like string for the value of the
157
+ # attribute +attr_name+. String attributes are truncated up to 50
158
+ # characters, Date and Time attributes are returned in the
159
+ # <tt>:db</tt> format, Array attributes are truncated up to 10 values.
160
+ # Other attributes return the value of <tt>#inspect</tt> without
161
+ # modification.
162
+ #
163
+ # person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
164
+ #
165
+ # person.attribute_for_inspect(:name)
166
+ # # => "\"David Heinemeier Hansson David Heinemeier Hansson ...\""
167
+ #
168
+ # person.attribute_for_inspect(:created_at)
169
+ # # => "\"2012-10-22 00:15:07\""
170
+ #
171
+ # person.attribute_for_inspect(:tag_ids)
172
+ # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]"
173
+ def attribute_for_inspect(attr_name)
174
+ value = self[attr_name]
175
+
176
+ if value.is_a?(String) && value.length > 50
177
+ "#{value[0, 50]}...".inspect
178
+ elsif value.is_a?(Date) || value.is_a?(Time)
179
+ %("#{value.to_s(:db)}")
180
+ elsif value.is_a?(Array) && value.size > 10
181
+ inspected = value.first(10).inspect
182
+ %(#{inspected[0...-1]}, ...])
183
+ else
184
+ value.inspect
185
+ end
186
+ end
187
+
188
+ # Returns +true+ if the specified +attribute+ has been set by the user or by a
189
+ # database load and is neither +nil+ nor <tt>empty?</tt> (the latter only applies
190
+ # to objects that respond to <tt>empty?</tt>, most notably Strings). Otherwise, +false+.
191
+ # Note that it always returns +true+ with boolean attributes.
192
+ #
193
+ # class Task < ActiveRecord::Base
194
+ # end
195
+ #
196
+ # task = Task.new(title: '', is_done: false)
197
+ # task.attribute_present?(:title) # => false
198
+ # task.attribute_present?(:is_done) # => true
199
+ # task.title = 'Buy milk'
200
+ # task.is_done = true
201
+ # task.attribute_present?(:title) # => true
202
+ # task.attribute_present?(:is_done) # => true
203
+ def attribute_present?(attribute)
204
+ value = self[attribute]
205
+ !value.nil? && !(value.respond_to?(:empty?) && value.empty?)
206
+ end
207
+
72
208
  # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
73
209
  # "2004-12-12" in a date column is cast to a date object, like Date.new(2004, 12, 12)). It raises
74
210
  # <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing.
@@ -103,39 +239,5 @@ module ActiveFedora
103
239
  def []=(attr_name, value)
104
240
  write_attribute(attr_name, value)
105
241
  end
106
-
107
- module ClassMethods
108
- def initialize_generated_modules # :nodoc:
109
- @generated_attribute_methods = Module.new { extend Mutex_m }
110
- include @generated_attribute_methods
111
- end
112
-
113
- # A method name is 'dangerous' if it is already (re)defined by Active Fedora, but
114
- # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
115
- def dangerous_attribute_method?(name) # :nodoc:
116
- method_defined_within?(name, Base)
117
- end
118
-
119
- def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
120
- if klass.method_defined?(name) || klass.private_method_defined?(name)
121
- if superklass.method_defined?(name) || superklass.private_method_defined?(name)
122
- klass.instance_method(name).owner != superklass.instance_method(name).owner
123
- else
124
- true
125
- end
126
- else
127
- false
128
- end
129
- end
130
-
131
- private
132
-
133
- # @param name [Symbol] name of the attribute to generate
134
- def generate_method(name)
135
- generated_attribute_methods.synchronize do
136
- define_attribute_methods name
137
- end
138
- end
139
- end
140
242
  end
141
243
  end
@@ -1,61 +1,46 @@
1
1
  module ActiveFedora
2
2
  module AttributeMethods
3
3
  module Read
4
- ReaderMethodCache = Class.new(AttributeMethodCache) do
5
- private
6
-
7
- # We want to generate the methods via module_eval rather than
8
- # define_method, because define_method is slower on dispatch.
9
- # Evaluating many similar methods may use more memory as the instruction
10
- # sequences are duplicated and cached (in MRI). define_method may
11
- # be slower on dispatch, but if you're careful about the closure
12
- # created, then define_method will consume much less memory.
13
- #
14
- # But sometimes the database might return columns with
15
- # characters that are not allowed in normal method names (like
16
- # 'my_column(omg)'. So to work around this we first define with
17
- # the __temp__ identifier, and then use alias method to rename
18
- # it to what we want.
19
- #
20
- # We are also defining a constant to hold the frozen string of
21
- # the attribute name. Using a constant means that we do not have
22
- # to allocate an object on each call to the attribute method.
23
- # Making it frozen means that it doesn't get duped when used to
24
- # key the @attributes_cache in read_attribute.
25
- def method_body(method_name, const_name)
26
- <<-EOMETHOD
27
- def #{method_name}
28
- name = ::ActiveFedora::AttributeMethods::AttrNames::ATTR_#{const_name}
29
- read_attribute(name) { |n| missing_attribute(n, caller) }
4
+ module ClassMethods
5
+ protected
6
+
7
+ def define_method_attribute(name)
8
+ name = name.to_s
9
+ safe_name = name.unpack('h*'.freeze).first
10
+ temp_method = "__temp__#{safe_name}"
11
+
12
+ ActiveFedora::AttributeMethods::AttrNames.set_name_cache safe_name, name
13
+
14
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
15
+ def #{temp_method}
16
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
17
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
18
+ end
19
+ STR
20
+
21
+ generated_attribute_methods.module_eval do
22
+ alias_method name, temp_method
23
+ undef_method temp_method
24
+ end
30
25
  end
31
- EOMETHOD
32
- end
33
- end.new
26
+ end
34
27
 
35
28
  extend ActiveSupport::Concern
36
29
 
37
30
  # Returns the value of the attribute identified by <tt>attr_name</tt> after
38
31
  # it has been typecast (for example, "2004-12-12" in a date column is cast
39
32
  # to a date object, like Date.new(2004, 12, 12)).
40
- def read_attribute(attr_name)
33
+ def read_attribute(attr_name, &block)
41
34
  name = attr_name.to_s
42
- @attributes.fetch(name, nil)
35
+ _read_attribute(name, &block)
43
36
  end
44
37
 
45
- private
46
-
47
- def attribute(attribute_name)
48
- read_attribute(attribute_name)
49
- end
38
+ def _read_attribute(attr_name) # :nodoc:
39
+ @attributes.fetch(attr_name.to_s) { |n| yield n if block_given? }
40
+ end
50
41
 
51
- module ClassMethods
52
- def define_method_attribute(name)
53
- method = ReaderMethodCache[name.to_s]
54
- generated_attribute_methods.module_eval do
55
- define_method name, method
56
- end
57
- end
58
- end
42
+ alias attribute _read_attribute
43
+ private :attribute
59
44
  end
60
45
  end
61
46
  end