activerecord 3.0.0.beta2 → 3.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +11 -1
- data/lib/active_record/associations.rb +26 -54
- data/lib/active_record/associations/association_collection.rb +13 -2
- data/lib/active_record/associations/association_proxy.rb +3 -1
- data/lib/active_record/associations/through_association_scope.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +6 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -4
- data/lib/active_record/base.rb +66 -62
- data/lib/active_record/callbacks.rb +4 -2
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +45 -45
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/named_scope.rb +26 -109
- data/lib/active_record/railties/databases.rake +3 -7
- data/lib/active_record/reflection.rb +11 -0
- data/lib/active_record/relation.rb +20 -1
- data/lib/active_record/relation/finder_methods.rb +18 -2
- data/lib/active_record/relation/predicate_builder.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +26 -8
- data/lib/active_record/relation/spawn_methods.rb +9 -6
- data/lib/active_record/serializers/xml_serializer.rb +2 -1
- data/lib/active_record/validations/uniqueness.rb +3 -1
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
- metadata +8 -7
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# Callbacks are hooks into the lifecycle of an Active Record object that allow you to trigger logic
|
3
5
|
# before or after an alteration of the object state. This can be used to make sure that associated and
|
@@ -250,7 +252,7 @@ module ActiveRecord
|
|
250
252
|
def before_validation(*args, &block)
|
251
253
|
options = args.last
|
252
254
|
if options.is_a?(Hash) && options[:on]
|
253
|
-
options[:if] = Array(options[:if])
|
255
|
+
options[:if] = Array.wrap(options[:if])
|
254
256
|
options[:if] << "@_on_validate == :#{options[:on]}"
|
255
257
|
end
|
256
258
|
set_callback(:validation, :before, *args, &block)
|
@@ -259,7 +261,7 @@ module ActiveRecord
|
|
259
261
|
def after_validation(*args, &block)
|
260
262
|
options = args.extract_options!
|
261
263
|
options[:prepend] = true
|
262
|
-
options[:if] = Array(options[:if])
|
264
|
+
options[:if] = Array.wrap(options[:if])
|
263
265
|
options[:if] << "!halted && value != false"
|
264
266
|
options[:if] << "@_on_validate == :#{options[:on]}" if options[:on]
|
265
267
|
set_callback(:validation, :after, *(args << options), &block)
|
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
15
15
|
|
16
16
|
def dirties_query_cache(base, *method_names)
|
17
17
|
method_names.each do |method_name|
|
18
|
-
base.class_eval <<-end_code, __FILE__, __LINE__
|
18
|
+
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
19
19
|
def #{method_name}_with_query_dirty(*args) # def update_with_query_dirty(*args)
|
20
20
|
clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
|
21
21
|
#{method_name}_without_query_dirty(*args) # update_without_query_dirty(*args)
|
@@ -32,7 +32,6 @@ module ActiveRecord
|
|
32
32
|
# Enable the query cache within the block.
|
33
33
|
def cache
|
34
34
|
old, @query_cache_enabled = @query_cache_enabled, true
|
35
|
-
@query_cache ||= {}
|
36
35
|
yield
|
37
36
|
ensure
|
38
37
|
clear_query_cache
|
@@ -54,7 +53,7 @@ module ActiveRecord
|
|
54
53
|
# the same SQL query and repeatedly return the same result each time, silently
|
55
54
|
# undermining the randomness you were expecting.
|
56
55
|
def clear_query_cache
|
57
|
-
@query_cache.clear
|
56
|
+
@query_cache.clear
|
58
57
|
end
|
59
58
|
|
60
59
|
def select_all_with_query_cache(*args)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module SchemaStatements
|
@@ -267,7 +269,7 @@ module ActiveRecord
|
|
267
269
|
# generates
|
268
270
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
269
271
|
def add_index(table_name, column_name, options = {})
|
270
|
-
column_names = Array(column_name)
|
272
|
+
column_names = Array.wrap(column_name)
|
271
273
|
index_name = index_name(table_name, :column => column_names)
|
272
274
|
|
273
275
|
if Hash === options # legacy support, since this param was a string
|
@@ -291,13 +293,13 @@ module ActiveRecord
|
|
291
293
|
# Remove the index named by_branch_party in the accounts table.
|
292
294
|
# remove_index :accounts, :name => :by_branch_party
|
293
295
|
def remove_index(table_name, options = {})
|
294
|
-
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{table_name}"
|
296
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{quote_table_name(table_name)}"
|
295
297
|
end
|
296
298
|
|
297
299
|
def index_name(table_name, options) #:nodoc:
|
298
300
|
if Hash === options # legacy support
|
299
301
|
if options[:column]
|
300
|
-
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
302
|
+
"index_#{table_name}_on_#{Array.wrap(options[:column]) * '_and_'}"
|
301
303
|
elsif options[:name]
|
302
304
|
options[:name]
|
303
305
|
else
|
@@ -54,6 +54,12 @@ module ActiveRecord
|
|
54
54
|
super(name, self.class.extract_value_from_default(default), sql_type, null)
|
55
55
|
end
|
56
56
|
|
57
|
+
# :stopdoc:
|
58
|
+
class << self
|
59
|
+
attr_accessor :money_precision
|
60
|
+
end
|
61
|
+
# :startdoc:
|
62
|
+
|
57
63
|
private
|
58
64
|
def extract_limit(sql_type)
|
59
65
|
case sql_type
|
@@ -71,9 +77,11 @@ module ActiveRecord
|
|
71
77
|
|
72
78
|
# Extracts the precision from PostgreSQL-specific data types.
|
73
79
|
def extract_precision(sql_type)
|
74
|
-
|
75
|
-
|
76
|
-
|
80
|
+
if sql_type == 'money'
|
81
|
+
self.class.money_precision
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
77
85
|
end
|
78
86
|
|
79
87
|
# Maps PostgreSQL-specific data types to logical Rails types.
|
@@ -83,18 +91,18 @@ module ActiveRecord
|
|
83
91
|
when /^(?:real|double precision)$/
|
84
92
|
:float
|
85
93
|
# Monetary types
|
86
|
-
when
|
94
|
+
when 'money'
|
87
95
|
:decimal
|
88
96
|
# Character types
|
89
97
|
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
|
90
98
|
:string
|
91
99
|
# Binary data types
|
92
|
-
when
|
100
|
+
when 'bytea'
|
93
101
|
:binary
|
94
102
|
# Date/time types
|
95
103
|
when /^timestamp with(?:out)? time zone$/
|
96
104
|
:datetime
|
97
|
-
when
|
105
|
+
when 'interval'
|
98
106
|
:string
|
99
107
|
# Geometric types
|
100
108
|
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
|
@@ -106,16 +114,16 @@ module ActiveRecord
|
|
106
114
|
when /^bit(?: varying)?(?:\(\d+\))?$/
|
107
115
|
:string
|
108
116
|
# XML type
|
109
|
-
when
|
117
|
+
when 'xml'
|
110
118
|
:xml
|
111
119
|
# Arrays
|
112
120
|
when /^\D+\[\]$/
|
113
121
|
:string
|
114
122
|
# Object identifier types
|
115
|
-
when
|
123
|
+
when 'oid'
|
116
124
|
:integer
|
117
125
|
# UUID type
|
118
|
-
when
|
126
|
+
when 'uuid'
|
119
127
|
:string
|
120
128
|
# Small and big integer types
|
121
129
|
when /^(?:small|big)int$/
|
@@ -383,9 +391,9 @@ module ActiveRecord
|
|
383
391
|
def quote(value, column = nil) #:nodoc:
|
384
392
|
if value.kind_of?(String) && column && column.type == :binary
|
385
393
|
"#{quoted_string_prefix}'#{escape_bytea(value)}'"
|
386
|
-
elsif value.kind_of?(String) && column && column.sql_type
|
394
|
+
elsif value.kind_of?(String) && column && column.sql_type == 'xml'
|
387
395
|
"xml E'#{quote_string(value)}'"
|
388
|
-
elsif value.kind_of?(Numeric) && column && column.sql_type
|
396
|
+
elsif value.kind_of?(Numeric) && column && column.sql_type == 'money'
|
389
397
|
# Not truly string input, so doesn't require (or allow) escape string syntax.
|
390
398
|
"'#{value.to_s}'"
|
391
399
|
elsif value.kind_of?(String) && column && column.sql_type =~ /^bit/
|
@@ -658,33 +666,34 @@ module ActiveRecord
|
|
658
666
|
end
|
659
667
|
end
|
660
668
|
|
661
|
-
# Creates a schema for the given user
|
662
|
-
#
|
663
|
-
# Example:
|
664
|
-
# create_schema('products', 'postgres')
|
665
|
-
def create_schema(schema_name, pg_username)
|
666
|
-
execute("CREATE SCHEMA \"#{schema_name}\" AUTHORIZATION \"#{pg_username}\"")
|
667
|
-
end
|
668
|
-
|
669
|
-
# Drops a schema
|
670
|
-
#
|
671
|
-
# Example:
|
672
|
-
# drop_schema('products')
|
673
|
-
def drop_schema(schema_name)
|
674
|
-
execute("DROP SCHEMA \"#{schema_name}\"")
|
675
|
-
end
|
676
|
-
|
677
|
-
# Returns an array of all schemas in the database
|
678
|
-
def all_schemas
|
679
|
-
query('SELECT schema_name FROM information_schema.schemata').flatten
|
680
|
-
end
|
681
|
-
|
682
669
|
# Returns the list of all tables in the schema search path or a specified schema.
|
683
670
|
def tables(name = nil)
|
684
671
|
query(<<-SQL, name).map { |row| row[0] }
|
685
672
|
SELECT tablename
|
673
|
+
FROM pg_tables
|
674
|
+
WHERE schemaname = ANY (current_schemas(false))
|
675
|
+
SQL
|
676
|
+
end
|
677
|
+
|
678
|
+
def table_exists?(name)
|
679
|
+
name = name.to_s
|
680
|
+
schema, table = name.split('.', 2)
|
681
|
+
|
682
|
+
unless table # A table was provided without a schema
|
683
|
+
table = schema
|
684
|
+
schema = nil
|
685
|
+
end
|
686
|
+
|
687
|
+
if name =~ /^"/ # Handle quoted table names
|
688
|
+
table = name
|
689
|
+
schema = nil
|
690
|
+
end
|
691
|
+
|
692
|
+
query(<<-SQL).first[0].to_i > 0
|
693
|
+
SELECT COUNT(*)
|
686
694
|
FROM pg_tables
|
687
|
-
|
695
|
+
WHERE tablename = '#{table.gsub(/(^"|"$)/,'')}'
|
696
|
+
#{schema ? "AND schemaname = '#{schema}'" : ''}
|
688
697
|
SQL
|
689
698
|
end
|
690
699
|
|
@@ -946,7 +955,7 @@ module ActiveRecord
|
|
946
955
|
# Construct a clean list of column names from the ORDER BY clause, removing
|
947
956
|
# any ASC/DESC modifiers
|
948
957
|
order_columns = order_by.split(',').collect { |s| s.split.first }
|
949
|
-
order_columns.delete_if
|
958
|
+
order_columns.delete_if(&:blank?)
|
950
959
|
order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
|
951
960
|
|
952
961
|
# Return a DISTINCT ON() clause that's distinct on the columns we want but includes
|
@@ -1010,17 +1019,8 @@ module ActiveRecord
|
|
1010
1019
|
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
|
1011
1020
|
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
|
1012
1021
|
# should know about this but can't detect it there, so deal with it here.
|
1013
|
-
money_precision =
|
1014
|
-
|
1015
|
-
def extract_precision(sql_type) # def extract_precision(sql_type)
|
1016
|
-
if sql_type =~ /^money$/ # if sql_type =~ /^money$/
|
1017
|
-
#{money_precision} # 19
|
1018
|
-
else # else
|
1019
|
-
super # super
|
1020
|
-
end # end
|
1021
|
-
end # end
|
1022
|
-
end_eval
|
1023
|
-
|
1022
|
+
PostgreSQLColumn.money_precision =
|
1023
|
+
(postgresql_version >= 80300) ? 19 : 10
|
1024
1024
|
configure_connection
|
1025
1025
|
end
|
1026
1026
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/array'
|
2
2
|
require 'active_support/core_ext/hash/except'
|
3
|
-
require 'active_support/core_ext/
|
3
|
+
require 'active_support/core_ext/kernel/singleton_class'
|
4
4
|
require 'active_support/core_ext/object/blank'
|
5
5
|
|
6
6
|
module ActiveRecord
|
@@ -8,16 +8,15 @@ module ActiveRecord
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
-
# Returns
|
11
|
+
# Returns an anonymous scope.
|
12
12
|
#
|
13
13
|
# posts = Post.scoped
|
14
14
|
# posts.size # Fires "select count(*) from posts" and returns the count
|
15
15
|
# posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
|
16
16
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# shirts = shirts.scoped(:include => :washing_instructions)
|
17
|
+
# fruits = Fruit.scoped
|
18
|
+
# fruits = fruits.where(:colour => 'red') if options[:red_only]
|
19
|
+
# fruits = fruits.limit(10) if limited?
|
21
20
|
#
|
22
21
|
# Anonymous \scopes tend to be useful when procedurally generating complex queries, where passing
|
23
22
|
# intermediate values (scopes) around as first-class objects is convenient.
|
@@ -25,7 +24,8 @@ module ActiveRecord
|
|
25
24
|
# You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
|
26
25
|
def scoped(options = {}, &block)
|
27
26
|
if options.present?
|
28
|
-
|
27
|
+
relation = scoped.apply_finder_options(options)
|
28
|
+
block_given? ? relation.extending(Module.new(&block)) : relation
|
29
29
|
else
|
30
30
|
current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.clone
|
31
31
|
end
|
@@ -36,21 +36,21 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
|
38
38
|
# Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
|
39
|
-
# such as <tt
|
39
|
+
# such as <tt>where(:color => :red).select('shirts.*').includes(:washing_instructions)</tt>.
|
40
40
|
#
|
41
41
|
# class Shirt < ActiveRecord::Base
|
42
|
-
# scope :red, :
|
43
|
-
# scope :dry_clean_only,
|
42
|
+
# scope :red, where(:color => 'red')
|
43
|
+
# scope :dry_clean_only, joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true)
|
44
44
|
# end
|
45
45
|
#
|
46
46
|
# The above calls to <tt>scope</tt> define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red,
|
47
|
-
# in effect, represents the query <tt>Shirt.
|
47
|
+
# in effect, represents the query <tt>Shirt.where(:color => 'red')</tt>.
|
48
48
|
#
|
49
49
|
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by Shirt.red is not an Array; it resembles the association object
|
50
|
-
# constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.
|
51
|
-
# <tt>Shirt.red.
|
52
|
-
#
|
53
|
-
#
|
50
|
+
# constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
|
51
|
+
# <tt>Shirt.red.where(:size => 'small')</tt>. Also, just as with the association objects, named \scopes act like an Array,
|
52
|
+
# implementing Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt>
|
53
|
+
# all behave as if Shirt.red really was an Array.
|
54
54
|
#
|
55
55
|
# These named \scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only.
|
56
56
|
# Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments
|
@@ -69,9 +69,7 @@ module ActiveRecord
|
|
69
69
|
# Named \scopes can also be procedural:
|
70
70
|
#
|
71
71
|
# class Shirt < ActiveRecord::Base
|
72
|
-
# scope :colored, lambda {
|
73
|
-
# { :conditions => { :color => color } }
|
74
|
-
# }
|
72
|
+
# scope :colored, lambda {|color| where(:color => color) }
|
75
73
|
# end
|
76
74
|
#
|
77
75
|
# In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
|
@@ -79,26 +77,13 @@ module ActiveRecord
|
|
79
77
|
# Named \scopes can also have extensions, just as with <tt>has_many</tt> declarations:
|
80
78
|
#
|
81
79
|
# class Shirt < ActiveRecord::Base
|
82
|
-
# scope :red, :
|
80
|
+
# scope :red, where(:color => 'red') do
|
83
81
|
# def dom_id
|
84
82
|
# 'red_shirts'
|
85
83
|
# end
|
86
84
|
# end
|
87
85
|
# end
|
88
|
-
|
89
|
-
#
|
90
|
-
# For testing complex named \scopes, you can examine the scoping options using the
|
91
|
-
# <tt>proxy_options</tt> method on the proxy itself.
|
92
|
-
#
|
93
|
-
# class Shirt < ActiveRecord::Base
|
94
|
-
# scope :colored, lambda { |color|
|
95
|
-
# { :conditions => { :color => color } }
|
96
|
-
# }
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# expected_options = { :conditions => { :colored => 'red' } }
|
100
|
-
# assert_equal expected_options, Shirt.colored('red').proxy_options
|
101
|
-
def scope(name, options = {}, &block)
|
86
|
+
def scope(name, scope_options = {}, &block)
|
102
87
|
name = name.to_sym
|
103
88
|
|
104
89
|
if !scopes[name] && respond_to?(name, true)
|
@@ -106,17 +91,17 @@ module ActiveRecord
|
|
106
91
|
"Overwriting existing method #{self.name}.#{name}."
|
107
92
|
end
|
108
93
|
|
109
|
-
scopes[name] = lambda do
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end, &block)
|
94
|
+
scopes[name] = lambda do |*args|
|
95
|
+
options = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
|
96
|
+
|
97
|
+
relation = scoped
|
98
|
+
relation = options.is_a?(Hash) ? relation.apply_finder_options(options) : scoped.merge(options) if options
|
99
|
+
block_given? ? relation.extending(Module.new(&block)) : relation
|
116
100
|
end
|
101
|
+
|
117
102
|
singleton_class.instance_eval do
|
118
103
|
define_method name do |*args|
|
119
|
-
scopes[name].call(
|
104
|
+
scopes[name].call(*args)
|
120
105
|
end
|
121
106
|
end
|
122
107
|
end
|
@@ -127,73 +112,5 @@ module ActiveRecord
|
|
127
112
|
end
|
128
113
|
end
|
129
114
|
|
130
|
-
class Scope < Relation
|
131
|
-
attr_accessor :current_scoped_methods_when_defined
|
132
|
-
|
133
|
-
delegate :scopes, :with_scope, :with_exclusive_scope, :scoped_methods, :scoped, :to => :klass
|
134
|
-
|
135
|
-
def self.init(klass, options, &block)
|
136
|
-
relation = new(klass, klass.arel_table)
|
137
|
-
|
138
|
-
scope = if options.is_a?(Hash)
|
139
|
-
klass.scoped.apply_finder_options(options.except(:extend))
|
140
|
-
else
|
141
|
-
options ? klass.scoped.merge(options) : klass.scoped
|
142
|
-
end
|
143
|
-
|
144
|
-
relation = relation.merge(scope)
|
145
|
-
|
146
|
-
Array.wrap(options[:extend]).each {|extension| relation.send(:extend, extension) } if options.is_a?(Hash)
|
147
|
-
relation.send(:extend, Module.new(&block)) if block_given?
|
148
|
-
|
149
|
-
relation.current_scoped_methods_when_defined = klass.send(:current_scoped_methods)
|
150
|
-
relation
|
151
|
-
end
|
152
|
-
|
153
|
-
def first(*args)
|
154
|
-
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
155
|
-
to_a.first(*args)
|
156
|
-
else
|
157
|
-
args.first.present? ? apply_finder_options(args.first).first : super
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def last(*args)
|
162
|
-
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
163
|
-
to_a.last(*args)
|
164
|
-
else
|
165
|
-
args.first.present? ? apply_finder_options(args.first).last : super
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def ==(other)
|
170
|
-
case other
|
171
|
-
when Scope
|
172
|
-
to_sql == other.to_sql
|
173
|
-
when Relation
|
174
|
-
other == self
|
175
|
-
when Array
|
176
|
-
to_a == other.to_a
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
private
|
181
|
-
|
182
|
-
def method_missing(method, *args, &block)
|
183
|
-
if klass.respond_to?(method)
|
184
|
-
with_scope(self) do
|
185
|
-
if current_scoped_methods_when_defined && !scoped_methods.include?(current_scoped_methods_when_defined) && !scopes.include?(method)
|
186
|
-
with_scope(current_scoped_methods_when_defined) { klass.send(method, *args, &block) }
|
187
|
-
else
|
188
|
-
klass.send(method, *args, &block)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
else
|
192
|
-
super
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
end
|
197
|
-
|
198
115
|
end
|
199
116
|
end
|