1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
require 'active_support/concern'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/class/attribute_accessors'
module ActiveModel
# This API is for Rails' internal use and is not currently considered 'public', so
# it may change in the future without warning.
#
# It creates configuration attributes that can be inherited from a module down
# to a class that includes the module. E.g.
#
# module MyModel
# extend ActiveModel::Configuration
# config_attribute :awesome
# self.awesome = true
# end
#
# class Post
# include MyModel
# end
#
# Post.awesome # => true
#
# Post.awesome = false
# Post.awesome # => false
# MyModel.awesome # => true
#
# We assume that the module will have a ClassMethods submodule containing methods
# to be transferred to the including class' singleton class.
#
# Config options can also be defined directly on a class:
#
# class Post
# extend ActiveModel::Configuration
# config_attribute :awesome
# end
#
# So this allows us to define a module that doesn't care about whether it is being
# included in a class or a module:
#
# module Awesomeness
# extend ActiveSupport::Concern
#
# included do
# extend ActiveModel::Configuration
# config_attribute :awesome
# self.awesome = true
# end
# end
#
# class Post
# include Awesomeness
# end
#
# module AwesomeModel
# include Awesomeness
# end
module Configuration #:nodoc:
def config_attribute(name, options = {})
klass = self.is_a?(Class) ? ClassAttribute : ModuleAttribute
klass.new(self, name, options).define
end
class Attribute
attr_reader :host, :name, :options
def initialize(host, name, options)
@host, @name, @options = host, name, options
end
def instance_writer?
options.fetch(:instance_writer, false)
end
end
class ClassAttribute < Attribute
def define
if options[:global]
host.cattr_accessor name, :instance_writer => instance_writer?
else
host.class_attribute name, :instance_writer => instance_writer?
end
end
end
class ModuleAttribute < Attribute
def class_methods
@class_methods ||= begin
if host.const_defined?(:ClassMethods, false)
host.const_get(:ClassMethods)
else
host.const_set(:ClassMethods, Module.new)
end
end
end
def define
host.singleton_class.class_eval <<-CODE, __FILE__, __LINE__ + 1
attr_accessor :#{name}
def #{name}?; !!#{name}; end
CODE
name, host = self.name, self.host
class_methods.class_eval do
define_method(name) { host.send(name) }
define_method("#{name}?") { !!send(name) }
end
host.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}; defined?(@#{name}) ? @#{name} : self.class.#{name}; end
def #{name}?; !!#{name}; end
CODE
if options[:global]
class_methods.class_eval do
define_method("#{name}=") { |val| host.send("#{name}=", val) }
end
else
class_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}=(val)
singleton_class.class_eval do
remove_possible_method(:#{name})
define_method(:#{name}) { val }
end
end
CODE
end
host.send(:attr_writer, name) if instance_writer?
end
end
end
end
|