rapid-core 0.1
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.
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +53 -0
- data/Rakefile +61 -0
- data/cucumber.yml +3 -0
- data/doc/plan.txt +89 -0
- data/doc/scaffold/controller.rb +83 -0
- data/doc/scaffold/helper.rb +2 -0
- data/doc/scaffold/model.rb +5 -0
- data/doc/scaffold/rapid_scaffold.rb +5 -0
- data/doc/scaffold/views/_form.html.erb +25 -0
- data/doc/scaffold/views/edit.html.erb +6 -0
- data/doc/scaffold/views/index.html.erb +25 -0
- data/doc/scaffold/views/new.html.erb +5 -0
- data/doc/scaffold/views/show.html.erb +15 -0
- data/features/settings/boolean/default.feature +36 -0
- data/features/settings/double-nested/default.feature +50 -0
- data/features/settings/double-nested/if.feature +41 -0
- data/features/settings/double-nested/unless.feature +39 -0
- data/features/settings/double-nested/validates/exclusion_of.feature +30 -0
- data/features/settings/double-nested/validates/format_of.feature +30 -0
- data/features/settings/double-nested/validates/inclusion_of.feature +30 -0
- data/features/settings/double-nested/validates/length_of.feature +30 -0
- data/features/settings/double-nested/validates/presence_of.feature +37 -0
- data/features/settings/double-nested/validates/size_of.feature +30 -0
- data/features/settings/integer/default.feature +49 -0
- data/features/settings/nested/default.feature +50 -0
- data/features/settings/nested/if.feature +53 -0
- data/features/settings/nested/unless.feature +32 -0
- data/features/settings/nested/validates/exclusion_of.feature +30 -0
- data/features/settings/nested/validates/format_of.feature +30 -0
- data/features/settings/nested/validates/inclusion_of.feature +30 -0
- data/features/settings/nested/validates/length_of.feature +30 -0
- data/features/settings/nested/validates/presence_of.feature +37 -0
- data/features/settings/nested/validates/size_of.feature +30 -0
- data/features/settings/not_found.feature +33 -0
- data/features/settings/string/default.feature +36 -0
- data/features/settings/string/validates/exclusion_of.feature +30 -0
- data/features/settings/string/validates/format_of.feature +30 -0
- data/features/settings/string/validates/inclusion_of.feature +30 -0
- data/features/settings/string/validates/length_of.feature +30 -0
- data/features/settings/string/validates/presence_of.feature +37 -0
- data/features/settings/string/validates/size_of.feature +30 -0
- data/features/step_definitions/settings_steps.rb +92 -0
- data/features/step_definitions/skeleton_steps.rb +68 -0
- data/features/step_definitions/template_steps.rb +39 -0
- data/features/support/env.rb +6 -0
- data/features/templates/comment_if.feature +55 -0
- data/features/templates/comment_unless.feature +56 -0
- data/features/templates/for/for.feature +51 -0
- data/features/templates/if/else.feature +60 -0
- data/features/templates/if/elsif.feature +82 -0
- data/features/templates/if/if.feature +55 -0
- data/features/templates/namespaces/exist.feature +54 -0
- data/features/templates/static.feature +37 -0
- data/features/templates/variables.feature +61 -0
- data/lib/rapid/check.rb +162 -0
- data/lib/rapid/core.rb +37 -0
- data/lib/rapid/error.rb +84 -0
- data/lib/rapid/module.rb +35 -0
- data/lib/rapid/railtie.rb +18 -0
- data/lib/rapid/setting/base.rb +35 -0
- data/lib/rapid/setting/boolean_setting.rb +17 -0
- data/lib/rapid/setting/class_hash.rb +34 -0
- data/lib/rapid/setting/comments.rb +25 -0
- data/lib/rapid/setting/definer.rb +151 -0
- data/lib/rapid/setting/instance_hash.rb +132 -0
- data/lib/rapid/setting/instance_root.rb +107 -0
- data/lib/rapid/setting/integer_setting.rb +24 -0
- data/lib/rapid/setting/namespace/base.rb +113 -0
- data/lib/rapid/setting/namespace/instance.rb +84 -0
- data/lib/rapid/setting/nested_validations.rb +86 -0
- data/lib/rapid/setting/string_setting.rb +13 -0
- data/lib/rapid/settings.rb +129 -0
- data/lib/rapid/skeleton/base.rb +164 -0
- data/lib/rapid/skeleton/helpers/directory.rb +53 -0
- data/lib/rapid/skeleton/helpers/gem.rb +133 -0
- data/lib/rapid/skeleton/helpers/migration.rb +46 -0
- data/lib/rapid/skeleton/helpers/route.rb +115 -0
- data/lib/rapid/skeleton/helpers/script.rb +33 -0
- data/lib/rapid/skeleton/helpers/template.rb +73 -0
- data/lib/rapid/skeleton/helpers/view.rb +35 -0
- data/lib/rapid/spec/template.rb +104 -0
- data/lib/rapid/spec.rb +1 -0
- data/lib/rapid/tasks.rb +29 -0
- data/lib/rapid/template/base.rb +49 -0
- data/lib/rapid/template/node/base.rb +43 -0
- data/lib/rapid/template/node/comment_node.rb +42 -0
- data/lib/rapid/template/node/if_node.rb +109 -0
- data/lib/rapid/template/node/root.rb +51 -0
- data/lib/rapid/template/node/static.rb +29 -0
- data/lib/rapid/template/node/variable.rb +86 -0
- data/lib/rapid/template/parser.rb +167 -0
- data/lib/rapid/template/pulling/base.rb +91 -0
- data/lib/rapid/template/pulling/explicit.rb +92 -0
- data/lib/rapid/template/pulling/forgiving.rb +58 -0
- data/lib/rapid/version.rb +3 -0
- data/lib/rapid.rb +37 -0
- data/rapid-core.gemspec +26 -0
- data/spec/rapid/check_spec.rb +119 -0
- data/spec/rapid/error_spec.rb +14 -0
- data/spec/rapid/module_spec.rb +28 -0
- data/spec/rapid/setting/base_spec.rb +17 -0
- data/spec/rapid/setting/definer_spec.rb +318 -0
- data/spec/rapid/setting/instance_root_spec.rb +161 -0
- data/spec/rapid/setting/namespace/base_spec.rb +93 -0
- data/spec/rapid/setting/namespace/instance_spec.rb +12 -0
- data/spec/rapid/setting/nested_validations_spec.rb +72 -0
- data/spec/rapid/settings_spec.rb +51 -0
- data/spec/rapid/skeleton/base_spec.rb +224 -0
- data/spec/rapid/skeleton/helpers/directory_spec.rb +104 -0
- data/spec/rapid/skeleton/helpers/gem_spec.rb +180 -0
- data/spec/rapid/skeleton/helpers/migration_spec.rb +23 -0
- data/spec/rapid/skeleton/helpers/route_spec.rb +120 -0
- data/spec/rapid/skeleton/helpers/script_spec.rb +57 -0
- data/spec/rapid/skeleton/helpers/template_spec.rb +142 -0
- data/spec/rapid/skeleton/helpers/view_spec.rb +54 -0
- data/spec/rapid/spec/template_spec.rb +168 -0
- data/spec/rapid/template/base_spec.rb +290 -0
- data/spec/rapid/template/node/base_spec.rb +9 -0
- data/spec/rapid/template/node/comment_node_spec.rb +46 -0
- data/spec/rapid/template/node/if_node_spec.rb +28 -0
- data/spec/rapid/template/node/root_spec.rb +9 -0
- data/spec/rapid/template/node/static_spec.rb +17 -0
- data/spec/rapid/template/node/variable_spec.rb +87 -0
- data/spec/rapid/template/parser_spec.rb +187 -0
- data/spec/rapid/template/pulling/base_spec.rb +81 -0
- data/spec/rapid/template/pulling/explicit_spec.rb +33 -0
- data/spec/rapid/template/pulling/forgiving_spec.rb +132 -0
- data/spec/spec_helper.rb +10 -0
- metadata +325 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
module Rapid
|
2
|
+
module Setting
|
3
|
+
|
4
|
+
class InstanceHash
|
5
|
+
|
6
|
+
attr_reader :delegate, :klass, :assignment_exceptions
|
7
|
+
|
8
|
+
delegate :empty?, :to => :delegate
|
9
|
+
delegate :each, :to => :delegate
|
10
|
+
delegate :keys, :to => :delegate
|
11
|
+
delegate :values, :to => :delegate
|
12
|
+
delegate :to_hash, :to => :delegate
|
13
|
+
|
14
|
+
def initialize klass, hash = {}
|
15
|
+
@klass = klass
|
16
|
+
|
17
|
+
@delegate = HashWithIndifferentAccess.new hash
|
18
|
+
@assignment_exceptions = HashWithIndifferentAccess.new
|
19
|
+
load_defaults
|
20
|
+
load_namespaces
|
21
|
+
end
|
22
|
+
|
23
|
+
def [] key
|
24
|
+
@delegate[key]
|
25
|
+
end
|
26
|
+
|
27
|
+
def []= full_name, value
|
28
|
+
namespace_name, child_name = Rapid::Settings.extract_nested_namespace(full_name)
|
29
|
+
|
30
|
+
if namespace_name
|
31
|
+
load_nested_value namespace_name, child_name, value
|
32
|
+
value
|
33
|
+
else
|
34
|
+
new_value = load_base_value full_name, value
|
35
|
+
@delegate[full_name] = new_value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def namespaces
|
40
|
+
values = self.values.delete_if {|v| not v.is_a? Namespace::Instance }
|
41
|
+
values
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
hash = {}
|
46
|
+
@delegate.each do |key, value|
|
47
|
+
if value.is_a? Namespace::Instance
|
48
|
+
hash[key] = value.to_hash
|
49
|
+
else
|
50
|
+
hash[key] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
hash
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def load_nested_value namespace_name, child_name, value
|
59
|
+
class_setting = @klass[namespace_name]
|
60
|
+
if class_setting.nil?
|
61
|
+
raise Rapid::UnknownSettingError.new(namespace_name)
|
62
|
+
|
63
|
+
elsif !class_setting.is_a?(Namespace::Base)
|
64
|
+
raise Rapid::InvalidSettingError.new(class_setting, value)
|
65
|
+
end
|
66
|
+
|
67
|
+
namespace = @delegate[namespace_name]
|
68
|
+
namespace[child_name] = value
|
69
|
+
return child_name, value
|
70
|
+
|
71
|
+
rescue UnknownSettingError => e
|
72
|
+
@assignment_exceptions[namespace_name] = e
|
73
|
+
nil
|
74
|
+
rescue InvalidSettingError => e
|
75
|
+
@assignment_exceptions[namespace_name] = e
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_base_value name, value
|
80
|
+
class_setting = @klass[name]
|
81
|
+
if class_setting.nil?
|
82
|
+
raise Rapid::UnknownSettingError.new(name)
|
83
|
+
end
|
84
|
+
|
85
|
+
if class_setting.is_a? Namespace::Base
|
86
|
+
value[:empty] = false if value.is_a? Hash
|
87
|
+
result = load_namespace class_setting, value
|
88
|
+
else
|
89
|
+
result = class_setting.load value
|
90
|
+
end
|
91
|
+
|
92
|
+
@assignment_exceptions.delete name
|
93
|
+
result
|
94
|
+
|
95
|
+
rescue UnknownSettingError => e
|
96
|
+
@assignment_exceptions[name] = e
|
97
|
+
nil
|
98
|
+
rescue InvalidSettingError => e
|
99
|
+
@assignment_exceptions[name] = e
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def load_defaults
|
104
|
+
@klass.scalars.each do |scalar|
|
105
|
+
unless @delegate.has_key? scalar.name
|
106
|
+
@delegate[scalar.name] = scalar.default_value unless scalar.default_value.nil?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def load_namespaces
|
112
|
+
return unless @klass.respond_to? :namespaces
|
113
|
+
|
114
|
+
@klass.namespaces.each do |namespace|
|
115
|
+
value = @delegate[namespace.name] || {}
|
116
|
+
instance = load_namespace namespace, value
|
117
|
+
@delegate[namespace.name] = instance
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def load_namespace namespace, value
|
122
|
+
value = {:empty => true} if value == nil || value == false
|
123
|
+
value = {:empty => false} if value == true
|
124
|
+
value[:owner] = _root if value.is_a?(Hash) && respond_to?(:_root)
|
125
|
+
namespace.load value
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Rapid
|
2
|
+
module Setting
|
3
|
+
|
4
|
+
class InstanceRoot < InstanceHash
|
5
|
+
|
6
|
+
include ActiveModel::Validations
|
7
|
+
validate :validate_no_assignment_exceptions
|
8
|
+
validate :validate_nested_settings
|
9
|
+
|
10
|
+
attr_reader :_root
|
11
|
+
|
12
|
+
def initialize klass, owner = nil, hash = {}
|
13
|
+
@_root = owner
|
14
|
+
super klass, hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_binding
|
18
|
+
binding
|
19
|
+
end
|
20
|
+
|
21
|
+
def [] full_name
|
22
|
+
namespace_name, child_name = Rapid::Settings.extract_nested_namespace(full_name)
|
23
|
+
|
24
|
+
if namespace_name.nil?
|
25
|
+
super
|
26
|
+
else
|
27
|
+
namespace = @delegate[namespace_name]
|
28
|
+
namespace[child_name] if namespace
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def set? full_name
|
33
|
+
value = self[full_name]
|
34
|
+
|
35
|
+
if Setting::Namespace::Instance === value
|
36
|
+
!value.empty?
|
37
|
+
else
|
38
|
+
value != nil && value != false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_yaml yaml_content
|
43
|
+
hash = parse_yaml yaml_content
|
44
|
+
|
45
|
+
# yaml was empty
|
46
|
+
return true if hash == false
|
47
|
+
|
48
|
+
load_hash hash
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_hash hash
|
52
|
+
hash.each do |name, value|
|
53
|
+
self[name] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_yaml
|
60
|
+
dot_hash = to_dot_hash
|
61
|
+
|
62
|
+
if dot_hash.empty?
|
63
|
+
""
|
64
|
+
else
|
65
|
+
Settings.clean_yaml dot_hash.to_yaml
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_dot_hash
|
70
|
+
Rapid::Settings.to_dot_hash to_hash
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def parse_yaml yaml_content
|
76
|
+
YAML.load yaml_content
|
77
|
+
rescue ArgumentError => e
|
78
|
+
raise Rapid::InvalidYamlError.new(e.message)
|
79
|
+
end
|
80
|
+
|
81
|
+
def validate_no_assignment_exceptions
|
82
|
+
assignment_exceptions.each do |attribute, error|
|
83
|
+
self.errors.add attribute, error.validation_message
|
84
|
+
end
|
85
|
+
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_nested_settings
|
90
|
+
namespaces.each do |namespace|
|
91
|
+
next if namespace.valid?
|
92
|
+
|
93
|
+
namespace.errors.each do |attribute, errors|
|
94
|
+
errors.each do |error|
|
95
|
+
self.errors.add "#{namespace.klass.name}.#{attribute}", error
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rapid
|
2
|
+
module Setting
|
3
|
+
|
4
|
+
class IntegerSetting < Base
|
5
|
+
|
6
|
+
def load value
|
7
|
+
if value.is_a?(String) && !(value =~ /[0-9]+/)
|
8
|
+
raise InvalidSettingError.new(self, value)
|
9
|
+
|
10
|
+
elsif value.is_a?(Float)
|
11
|
+
raise InvalidSettingError.new(self, value)
|
12
|
+
|
13
|
+
elsif value.nil?
|
14
|
+
nil
|
15
|
+
|
16
|
+
else
|
17
|
+
value.to_i
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Rapid
|
2
|
+
module Setting
|
3
|
+
module Namespace
|
4
|
+
|
5
|
+
class Base < Setting::Base
|
6
|
+
|
7
|
+
attr_accessor :delegate, :instance_class, :default_empty
|
8
|
+
|
9
|
+
delegate :[], :to => :delegate
|
10
|
+
delegate :[]=, :to => :delegate
|
11
|
+
|
12
|
+
def initialize name, options = {}
|
13
|
+
super
|
14
|
+
@delegate = HashWithIndifferentAccess.new {}
|
15
|
+
@klass = options[:class]
|
16
|
+
@instance_class = define_instance_class if @klass
|
17
|
+
@default_empty = !options[:default] if options.key? :default
|
18
|
+
end
|
19
|
+
|
20
|
+
def namespaces
|
21
|
+
values = delegate.values
|
22
|
+
values.delete_if {|c| !c.is_a?(Namespace::Base) }
|
23
|
+
values
|
24
|
+
end
|
25
|
+
|
26
|
+
def scalars
|
27
|
+
values = delegate.values
|
28
|
+
values.delete_if {|c| c.is_a?(Namespace::Base) }
|
29
|
+
values
|
30
|
+
end
|
31
|
+
|
32
|
+
def load value
|
33
|
+
owner = value.delete :owner if value.is_a? Hash
|
34
|
+
|
35
|
+
if value != nil && !value.respond_to?(:to_hash)
|
36
|
+
raise InvalidSettingError.new(self, value)
|
37
|
+
end
|
38
|
+
|
39
|
+
hash = value.to_hash if value
|
40
|
+
|
41
|
+
if @instance_class
|
42
|
+
@instance_class.new owner, self, hash
|
43
|
+
else
|
44
|
+
Namespace::Instance.new owner, self, hash
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def define_setting setting
|
49
|
+
define_helper_methods_for setting
|
50
|
+
setting.namespace[setting.name] = setting
|
51
|
+
setting
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def instance_class_name
|
57
|
+
full_name.to_s.gsub('.', '/').camelize.gsub("::", "")
|
58
|
+
end
|
59
|
+
|
60
|
+
def define_instance_class
|
61
|
+
instance_class = eval %(
|
62
|
+
module #{@klass.name}::Settings
|
63
|
+
class #{instance_class_name} < Namespace::Instance
|
64
|
+
@setting_name = #{name.to_s.inspect}
|
65
|
+
@full_setting_name = #{full_name.to_s.inspect}
|
66
|
+
|
67
|
+
class << self ; attr_reader :setting_name, :full_setting_name ; end
|
68
|
+
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
)
|
73
|
+
|
74
|
+
instance_class
|
75
|
+
end
|
76
|
+
|
77
|
+
def define_helper_methods_for setting
|
78
|
+
name = setting.name
|
79
|
+
getter = setting.get_helper_name
|
80
|
+
setter = setting.set_helper_name
|
81
|
+
|
82
|
+
@instance_class.class_eval do
|
83
|
+
define_method getter do
|
84
|
+
self[name]
|
85
|
+
end
|
86
|
+
|
87
|
+
define_method setter do |value|
|
88
|
+
self[name] = value
|
89
|
+
end
|
90
|
+
|
91
|
+
if setting.is_a? BooleanSetting
|
92
|
+
define_method "#{getter}?" do
|
93
|
+
self[name] == true
|
94
|
+
end
|
95
|
+
elsif setting.is_a? Namespace::Base
|
96
|
+
define_method "#{getter}?" do
|
97
|
+
self[name] != nil && !self[name].empty?
|
98
|
+
end
|
99
|
+
else
|
100
|
+
define_method "#{getter}?" do
|
101
|
+
self[name] != nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Rapid
|
2
|
+
module Setting
|
3
|
+
module Namespace
|
4
|
+
|
5
|
+
class Instance < Setting::InstanceHash
|
6
|
+
|
7
|
+
include ActiveModel::Validations
|
8
|
+
validate :validate_nested_settings
|
9
|
+
validate :validate_no_assignment_exceptions
|
10
|
+
|
11
|
+
attr_reader :_root
|
12
|
+
|
13
|
+
def initialize root, klass, hash = {}
|
14
|
+
@_root = root
|
15
|
+
|
16
|
+
if hash.key? :empty
|
17
|
+
@default_empty = hash.delete :empty
|
18
|
+
@hardcoded_empty = @default_empty
|
19
|
+
elsif klass.default_empty != nil
|
20
|
+
@default_empty = klass.default_empty
|
21
|
+
else
|
22
|
+
@default_empty = true
|
23
|
+
end
|
24
|
+
|
25
|
+
super klass, hash
|
26
|
+
end
|
27
|
+
|
28
|
+
def root
|
29
|
+
@_root
|
30
|
+
end
|
31
|
+
|
32
|
+
def empty?
|
33
|
+
return @hardcoded_empty if defined? @hardcoded_empty
|
34
|
+
|
35
|
+
@delegate.each do |key, value|
|
36
|
+
if value.is_a? Instance
|
37
|
+
return false if not value.empty?
|
38
|
+
else
|
39
|
+
return false if value != nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
@default_empty
|
44
|
+
end
|
45
|
+
|
46
|
+
def [] full_name
|
47
|
+
namespace_name, child_name = Rapid::Settings.extract_nested_namespace(full_name)
|
48
|
+
|
49
|
+
if namespace_name.nil?
|
50
|
+
super
|
51
|
+
else
|
52
|
+
namespace = @delegate[namespace_name]
|
53
|
+
namespace[child_name] if namespace
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def validate_nested_settings
|
60
|
+
namespaces.each do |namespace|
|
61
|
+
next if namespace.valid?
|
62
|
+
|
63
|
+
namespace.errors.each do |attribute, errors|
|
64
|
+
errors.each do |error|
|
65
|
+
self.errors.add "#{namespace.klass.name}.#{attribute}", error
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_no_assignment_exceptions
|
74
|
+
assignment_exceptions.each do |attribute, error|
|
75
|
+
self.errors.add attribute, error.validation_message
|
76
|
+
end
|
77
|
+
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Rapid
|
2
|
+
module Setting
|
3
|
+
|
4
|
+
module NestedValidations
|
5
|
+
|
6
|
+
def self.included base
|
7
|
+
base.extend ClassMethods
|
8
|
+
|
9
|
+
base.class_eval do
|
10
|
+
class << self
|
11
|
+
alias_method_chain :validates_exclusion_of, :nesting
|
12
|
+
alias_method_chain :validates_format_of, :nesting
|
13
|
+
alias_method_chain :validates_inclusion_of, :nesting
|
14
|
+
alias_method_chain :validates_length_of, :nesting
|
15
|
+
alias_method_chain :validates_presence_of, :nesting
|
16
|
+
alias_method_chain :validates_size_of, :nesting
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
def validates_exclusion_of_with_nesting *args
|
27
|
+
options = args.extract_options!
|
28
|
+
nested_validations :validates_exclusion_of, args, options
|
29
|
+
end
|
30
|
+
|
31
|
+
def validates_format_of_with_nesting *args
|
32
|
+
options = args.extract_options!
|
33
|
+
nested_validations :validates_format_of, args, options
|
34
|
+
end
|
35
|
+
|
36
|
+
def validates_inclusion_of_with_nesting *args
|
37
|
+
options = args.extract_options!
|
38
|
+
nested_validations :validates_inclusion_of, args, options
|
39
|
+
end
|
40
|
+
|
41
|
+
def validates_length_of_with_nesting *args
|
42
|
+
options = args.extract_options!
|
43
|
+
nested_validations :validates_length_of, args, options
|
44
|
+
end
|
45
|
+
|
46
|
+
def validates_presence_of_with_nesting *args
|
47
|
+
options = args.extract_options!
|
48
|
+
nested_validations :validates_presence_of, args, options
|
49
|
+
end
|
50
|
+
|
51
|
+
def validates_size_of_with_nesting *args
|
52
|
+
options = args.extract_options!
|
53
|
+
nested_validations :validates_size_of, args, options
|
54
|
+
end
|
55
|
+
|
56
|
+
def nested_validations validation, attributes, options = {}
|
57
|
+
attributes.each do |attribute|
|
58
|
+
nested_validation validation, attribute, options
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def nested_validation validation, attribute, options = {}
|
63
|
+
names = attribute.to_s.split('.')
|
64
|
+
name = names.pop
|
65
|
+
|
66
|
+
if names.empty?
|
67
|
+
send "#{validation}_without_nesting", attribute, options
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
namespace = setting.find_namespace *names
|
72
|
+
klass = namespace.instance_class if namespace
|
73
|
+
|
74
|
+
if klass.nil?
|
75
|
+
raise UnknownSettingError.new(attribute)
|
76
|
+
end
|
77
|
+
|
78
|
+
klass.send validation, name, options
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'rapid/setting/nested_validations'
|
2
|
+
require 'rapid/setting/definer'
|
3
|
+
require 'rapid/setting/class_hash'
|
4
|
+
require 'rapid/setting/instance_hash'
|
5
|
+
require 'rapid/setting/instance_root'
|
6
|
+
|
7
|
+
require 'rapid/setting/base'
|
8
|
+
require 'rapid/setting/namespace/base'
|
9
|
+
require 'rapid/setting/namespace/instance'
|
10
|
+
require 'rapid/setting/boolean_setting'
|
11
|
+
require 'rapid/setting/string_setting'
|
12
|
+
require 'rapid/setting/integer_setting'
|
13
|
+
|
14
|
+
require 'rapid/setting/comments'
|
15
|
+
|
16
|
+
module Rapid
|
17
|
+
module Settings
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
def reserved_names
|
22
|
+
# ActiveModel::Validations
|
23
|
+
@reserved_words ||= %w(_validate_callbacks _validators errors read_attribute_for_validation
|
24
|
+
run_callbacks valid validates_acceptance_of validates_confirmation_of validates_exclusion_of
|
25
|
+
validates_format_of validates_inclusion_of validates_length_of validates_numericality_of
|
26
|
+
validates_presence_of validates_size_of validates_with validation_context) +
|
27
|
+
|
28
|
+
# internal
|
29
|
+
%w(_root empty namespaces scalars validate_nested_settings validate_no_assignment_exceptions
|
30
|
+
load_yaml load_hash to_yaml to_dot_hash to_hash parse_yaml get_binding)
|
31
|
+
end
|
32
|
+
|
33
|
+
def reserved_name? name
|
34
|
+
reserved_names.include? name.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def extract_nested_namespace full_name
|
38
|
+
return nil, nil if full_name.nil?
|
39
|
+
|
40
|
+
full_name = full_name.to_s
|
41
|
+
if full_name.to_s =~ /^([^\.]+)\.(.+)$/
|
42
|
+
return $1, $2
|
43
|
+
else
|
44
|
+
return nil, full_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def clean_yaml yaml
|
49
|
+
yaml.gsub! /^--- \n/, ""
|
50
|
+
yaml.gsub! /\n$/, ""
|
51
|
+
yaml
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_dot_hash nested_hash
|
55
|
+
dot_hash = {}
|
56
|
+
flatten = proc { |key, value|
|
57
|
+
|
58
|
+
if value.is_a?(Hash)
|
59
|
+
value.each do |k2, v2|
|
60
|
+
flatten[key + [k2], v2]
|
61
|
+
end
|
62
|
+
else
|
63
|
+
namespace = key.join('.')
|
64
|
+
dot_hash[namespace] = value
|
65
|
+
end
|
66
|
+
}
|
67
|
+
|
68
|
+
flatten[[], nested_hash]
|
69
|
+
dot_hash
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.included base
|
75
|
+
base.send :include, ActiveModel::Validations
|
76
|
+
base.send :include, Rapid::Setting::NestedValidations
|
77
|
+
base.send :include, Rapid::Setting::Comments
|
78
|
+
|
79
|
+
base.extend ClassMethods
|
80
|
+
|
81
|
+
base.validate :validate_settings
|
82
|
+
|
83
|
+
base.delegate :load_yaml, :to => :settings
|
84
|
+
base.delegate :load_hash, :to => :settings
|
85
|
+
base.delegate :to_yaml, :to => :settings
|
86
|
+
base.delegate :to_hash, :to => :settings
|
87
|
+
base.delegate :to_dot_hash, :to => :settings
|
88
|
+
base.delegate :[], :to => :settings
|
89
|
+
base.delegate :[]=, :to => :settings
|
90
|
+
base.delegate :set?, :to => :settings
|
91
|
+
end
|
92
|
+
|
93
|
+
def settings
|
94
|
+
@settings ||= Setting::InstanceRoot.new(self.class.settings, self)
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_binding
|
98
|
+
binding
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def validate_settings
|
104
|
+
unless settings.valid?
|
105
|
+
settings.errors.each do |attribute, errors|
|
106
|
+
errors.each {|error| self.errors.add attribute, error }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
module ClassMethods
|
114
|
+
|
115
|
+
def settings
|
116
|
+
@settings ||= Setting::ClassHash.new
|
117
|
+
end
|
118
|
+
|
119
|
+
protected
|
120
|
+
|
121
|
+
def setting
|
122
|
+
@setting ||= Setting::Definer.new(self)
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|