active-fedora 9.10.0.pre1 → 9.10.0.pre2

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: 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