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.
Files changed (132) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.lock +53 -0
  5. data/Rakefile +61 -0
  6. data/cucumber.yml +3 -0
  7. data/doc/plan.txt +89 -0
  8. data/doc/scaffold/controller.rb +83 -0
  9. data/doc/scaffold/helper.rb +2 -0
  10. data/doc/scaffold/model.rb +5 -0
  11. data/doc/scaffold/rapid_scaffold.rb +5 -0
  12. data/doc/scaffold/views/_form.html.erb +25 -0
  13. data/doc/scaffold/views/edit.html.erb +6 -0
  14. data/doc/scaffold/views/index.html.erb +25 -0
  15. data/doc/scaffold/views/new.html.erb +5 -0
  16. data/doc/scaffold/views/show.html.erb +15 -0
  17. data/features/settings/boolean/default.feature +36 -0
  18. data/features/settings/double-nested/default.feature +50 -0
  19. data/features/settings/double-nested/if.feature +41 -0
  20. data/features/settings/double-nested/unless.feature +39 -0
  21. data/features/settings/double-nested/validates/exclusion_of.feature +30 -0
  22. data/features/settings/double-nested/validates/format_of.feature +30 -0
  23. data/features/settings/double-nested/validates/inclusion_of.feature +30 -0
  24. data/features/settings/double-nested/validates/length_of.feature +30 -0
  25. data/features/settings/double-nested/validates/presence_of.feature +37 -0
  26. data/features/settings/double-nested/validates/size_of.feature +30 -0
  27. data/features/settings/integer/default.feature +49 -0
  28. data/features/settings/nested/default.feature +50 -0
  29. data/features/settings/nested/if.feature +53 -0
  30. data/features/settings/nested/unless.feature +32 -0
  31. data/features/settings/nested/validates/exclusion_of.feature +30 -0
  32. data/features/settings/nested/validates/format_of.feature +30 -0
  33. data/features/settings/nested/validates/inclusion_of.feature +30 -0
  34. data/features/settings/nested/validates/length_of.feature +30 -0
  35. data/features/settings/nested/validates/presence_of.feature +37 -0
  36. data/features/settings/nested/validates/size_of.feature +30 -0
  37. data/features/settings/not_found.feature +33 -0
  38. data/features/settings/string/default.feature +36 -0
  39. data/features/settings/string/validates/exclusion_of.feature +30 -0
  40. data/features/settings/string/validates/format_of.feature +30 -0
  41. data/features/settings/string/validates/inclusion_of.feature +30 -0
  42. data/features/settings/string/validates/length_of.feature +30 -0
  43. data/features/settings/string/validates/presence_of.feature +37 -0
  44. data/features/settings/string/validates/size_of.feature +30 -0
  45. data/features/step_definitions/settings_steps.rb +92 -0
  46. data/features/step_definitions/skeleton_steps.rb +68 -0
  47. data/features/step_definitions/template_steps.rb +39 -0
  48. data/features/support/env.rb +6 -0
  49. data/features/templates/comment_if.feature +55 -0
  50. data/features/templates/comment_unless.feature +56 -0
  51. data/features/templates/for/for.feature +51 -0
  52. data/features/templates/if/else.feature +60 -0
  53. data/features/templates/if/elsif.feature +82 -0
  54. data/features/templates/if/if.feature +55 -0
  55. data/features/templates/namespaces/exist.feature +54 -0
  56. data/features/templates/static.feature +37 -0
  57. data/features/templates/variables.feature +61 -0
  58. data/lib/rapid/check.rb +162 -0
  59. data/lib/rapid/core.rb +37 -0
  60. data/lib/rapid/error.rb +84 -0
  61. data/lib/rapid/module.rb +35 -0
  62. data/lib/rapid/railtie.rb +18 -0
  63. data/lib/rapid/setting/base.rb +35 -0
  64. data/lib/rapid/setting/boolean_setting.rb +17 -0
  65. data/lib/rapid/setting/class_hash.rb +34 -0
  66. data/lib/rapid/setting/comments.rb +25 -0
  67. data/lib/rapid/setting/definer.rb +151 -0
  68. data/lib/rapid/setting/instance_hash.rb +132 -0
  69. data/lib/rapid/setting/instance_root.rb +107 -0
  70. data/lib/rapid/setting/integer_setting.rb +24 -0
  71. data/lib/rapid/setting/namespace/base.rb +113 -0
  72. data/lib/rapid/setting/namespace/instance.rb +84 -0
  73. data/lib/rapid/setting/nested_validations.rb +86 -0
  74. data/lib/rapid/setting/string_setting.rb +13 -0
  75. data/lib/rapid/settings.rb +129 -0
  76. data/lib/rapid/skeleton/base.rb +164 -0
  77. data/lib/rapid/skeleton/helpers/directory.rb +53 -0
  78. data/lib/rapid/skeleton/helpers/gem.rb +133 -0
  79. data/lib/rapid/skeleton/helpers/migration.rb +46 -0
  80. data/lib/rapid/skeleton/helpers/route.rb +115 -0
  81. data/lib/rapid/skeleton/helpers/script.rb +33 -0
  82. data/lib/rapid/skeleton/helpers/template.rb +73 -0
  83. data/lib/rapid/skeleton/helpers/view.rb +35 -0
  84. data/lib/rapid/spec/template.rb +104 -0
  85. data/lib/rapid/spec.rb +1 -0
  86. data/lib/rapid/tasks.rb +29 -0
  87. data/lib/rapid/template/base.rb +49 -0
  88. data/lib/rapid/template/node/base.rb +43 -0
  89. data/lib/rapid/template/node/comment_node.rb +42 -0
  90. data/lib/rapid/template/node/if_node.rb +109 -0
  91. data/lib/rapid/template/node/root.rb +51 -0
  92. data/lib/rapid/template/node/static.rb +29 -0
  93. data/lib/rapid/template/node/variable.rb +86 -0
  94. data/lib/rapid/template/parser.rb +167 -0
  95. data/lib/rapid/template/pulling/base.rb +91 -0
  96. data/lib/rapid/template/pulling/explicit.rb +92 -0
  97. data/lib/rapid/template/pulling/forgiving.rb +58 -0
  98. data/lib/rapid/version.rb +3 -0
  99. data/lib/rapid.rb +37 -0
  100. data/rapid-core.gemspec +26 -0
  101. data/spec/rapid/check_spec.rb +119 -0
  102. data/spec/rapid/error_spec.rb +14 -0
  103. data/spec/rapid/module_spec.rb +28 -0
  104. data/spec/rapid/setting/base_spec.rb +17 -0
  105. data/spec/rapid/setting/definer_spec.rb +318 -0
  106. data/spec/rapid/setting/instance_root_spec.rb +161 -0
  107. data/spec/rapid/setting/namespace/base_spec.rb +93 -0
  108. data/spec/rapid/setting/namespace/instance_spec.rb +12 -0
  109. data/spec/rapid/setting/nested_validations_spec.rb +72 -0
  110. data/spec/rapid/settings_spec.rb +51 -0
  111. data/spec/rapid/skeleton/base_spec.rb +224 -0
  112. data/spec/rapid/skeleton/helpers/directory_spec.rb +104 -0
  113. data/spec/rapid/skeleton/helpers/gem_spec.rb +180 -0
  114. data/spec/rapid/skeleton/helpers/migration_spec.rb +23 -0
  115. data/spec/rapid/skeleton/helpers/route_spec.rb +120 -0
  116. data/spec/rapid/skeleton/helpers/script_spec.rb +57 -0
  117. data/spec/rapid/skeleton/helpers/template_spec.rb +142 -0
  118. data/spec/rapid/skeleton/helpers/view_spec.rb +54 -0
  119. data/spec/rapid/spec/template_spec.rb +168 -0
  120. data/spec/rapid/template/base_spec.rb +290 -0
  121. data/spec/rapid/template/node/base_spec.rb +9 -0
  122. data/spec/rapid/template/node/comment_node_spec.rb +46 -0
  123. data/spec/rapid/template/node/if_node_spec.rb +28 -0
  124. data/spec/rapid/template/node/root_spec.rb +9 -0
  125. data/spec/rapid/template/node/static_spec.rb +17 -0
  126. data/spec/rapid/template/node/variable_spec.rb +87 -0
  127. data/spec/rapid/template/parser_spec.rb +187 -0
  128. data/spec/rapid/template/pulling/base_spec.rb +81 -0
  129. data/spec/rapid/template/pulling/explicit_spec.rb +33 -0
  130. data/spec/rapid/template/pulling/forgiving_spec.rb +132 -0
  131. data/spec/spec_helper.rb +10 -0
  132. 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,13 @@
1
+ module Rapid
2
+ module Setting
3
+
4
+ class StringSetting < Base
5
+
6
+ def load value
7
+ value.nil? ? nil : value.to_s
8
+ end
9
+
10
+ end
11
+
12
+ end
13
+ 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