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,37 @@
1
+ Feature: push and pull a static template
2
+
3
+ Background:
4
+ Given a skeleton with settings "my_settings.rb":
5
+ """
6
+ class MySettings
7
+ include Rapid::Settings
8
+
9
+ end
10
+ """
11
+ And a template "static.erb":
12
+ """
13
+ class Foo < ActiveRecord::Base
14
+
15
+ def inspect
16
+ "foo"
17
+ end
18
+
19
+ end
20
+ """
21
+
22
+ Scenario: Push and Pull Template
23
+ When I push the skeleton through "static.erb" with:
24
+ """
25
+ """
26
+ Then I should get:
27
+ """
28
+ class Foo < ActiveRecord::Base
29
+
30
+ def inspect
31
+ "foo"
32
+ end
33
+
34
+ end
35
+ """
36
+ And vice versa
37
+
@@ -0,0 +1,61 @@
1
+ Feature: template with a variable
2
+
3
+ Background:
4
+ Given a skeleton with settings "my_settings.rb":
5
+ """
6
+ class MySettings
7
+ include Rapid::Settings
8
+
9
+ setting.string :name, :default => "Dan"
10
+ setting.integer :id, :default => 5
11
+ setting.string 'foo.bar', :default => 'hey'
12
+ setting.integer 'foo.baz', :default => 20
13
+
14
+ end
15
+ """
16
+ And a template "variables.erb":
17
+ """
18
+ class <%= name %> < ActiveRecord::Base
19
+
20
+ def inspect
21
+ "<%= id %> <%= foo.bar %> <%= foo.baz %>"
22
+ end
23
+
24
+ end
25
+ """
26
+
27
+ @wip
28
+ Scenario: Push/Pull Template
29
+ When I push the skeleton through "variables.erb" with:
30
+ """
31
+ name: Foo
32
+ foo.baz: 10
33
+ foo.bar: hi
34
+ id: 5
35
+ """
36
+ Then I should get:
37
+ """
38
+ class Foo < ActiveRecord::Base
39
+
40
+ def inspect
41
+ "5 hi 10"
42
+ end
43
+
44
+ end
45
+ """
46
+ And vice versa
47
+
48
+ Scenario: obey defaults
49
+ When I push the skeleton through "variables.erb" with:
50
+ """
51
+ """
52
+ Then I should get:
53
+ """
54
+ class Dan < ActiveRecord::Base
55
+
56
+ def inspect
57
+ "5 hey 20"
58
+ end
59
+
60
+ end
61
+ """
@@ -0,0 +1,162 @@
1
+ module Rapid
2
+
3
+ class Check
4
+
5
+ attr_reader :code, :ok_count, :warning_count, :error_count
6
+
7
+ def initialize code, options = {}
8
+ @code = code
9
+ @console_output = options[:console]
10
+ @ok_count = 0
11
+ @warning_count = 0
12
+ @error_count = 0
13
+ @sections = []
14
+ end
15
+
16
+ def check_count
17
+ ok_count + warning_count + error_count
18
+ end
19
+
20
+ def valid?
21
+ @valid = true
22
+ @ok_count = 0
23
+ @warning_count = 0
24
+ @error_count = 0
25
+
26
+ as_current { eval code }
27
+ @valid
28
+ end
29
+
30
+ def ok filename, message
31
+ @ok_count += 1
32
+ log :ok, filename, message
33
+ end
34
+
35
+ def warning filename, message
36
+ @warning_count += 1
37
+ log :warning, filename, message
38
+ end
39
+
40
+ def error filename, message
41
+ @error_count += 1
42
+ @valid = false
43
+ log :error, "", ""
44
+ log :error, filename, message
45
+ log :error, "", ""
46
+ end
47
+
48
+ def exception filename, e
49
+ @error_count += 1
50
+ @valid = false
51
+
52
+ log :error, "", ""
53
+ log :error, filename, ""
54
+ log :error, "", ""
55
+ log :error, " problem: ", "content doesn't match"
56
+ log :error, " after: ", pretty_code(e.previous_content, "START OF FILE")
57
+ log :error, " expected:", pretty_code(e.expected_content, "END OF FILE")
58
+ log :error, " received:", pretty_code(e.content, "END OF FILE")
59
+ log :error, " current: ", clean_hash(e.result)
60
+ log :error, "", ""
61
+ end
62
+
63
+ def with_section name
64
+ puts "" if @sections.empty?
65
+
66
+ indention = " " * @sections.length
67
+ puts "#{indention}#{name}"
68
+
69
+ @sections.push name
70
+ yield
71
+ ensure
72
+ @sections.pop
73
+ end
74
+
75
+ protected
76
+
77
+ def clean_hash hash
78
+ h = {}
79
+
80
+ hash.each do |key, value|
81
+ if String === value && value.length > 50
82
+ value = value[0..25] + "..." + value[-25..25]
83
+ end
84
+
85
+ h[key] = value
86
+ end
87
+
88
+ h.inspect
89
+ end
90
+
91
+ def pretty_code code, blank_replace
92
+ if code.blank?
93
+ blank_replace
94
+ else
95
+ code[0..100].inspect
96
+ end
97
+ end
98
+
99
+ def log type, filename, message
100
+ return unless @console_output
101
+
102
+ indention = " " * @sections.length
103
+
104
+ output = "#{indention}#{filename} #{message}"
105
+ Rapid.color_puts type, output
106
+ end
107
+
108
+ def as_current
109
+ self.class.current = self
110
+ yield
111
+
112
+ ensure
113
+ self.class.current = nil
114
+ end
115
+
116
+ class << self
117
+ attr_accessor :current, :file
118
+
119
+ def possible_files
120
+ [
121
+ '.rapid',
122
+ 'rapid.rb',
123
+ File.join('config', 'rapid.rb')
124
+ ]
125
+ end
126
+
127
+ def new_with_detection *args
128
+ filename = file
129
+
130
+ if filename.nil?
131
+ possible_files.each do |name|
132
+ if File.exists?(name) && !File.directory?(name)
133
+ filename ||= name
134
+ end
135
+ end
136
+ end
137
+
138
+ unless filename
139
+ raise FileNotFoundCheckError.new("could not locate your rapid.rb check file [#{Rapid::Check.possible_files.join(', ')}]. " +
140
+ "Please create it or set the location using Rapid::Check.file = '/config/checks.rb'.")
141
+ end
142
+
143
+ code = File.open(filename) {|f| f.read }
144
+ new code, *args
145
+ end
146
+
147
+ def encounters_error?
148
+ if current.nil?
149
+ yield
150
+ false
151
+ else
152
+ old_count = current.error_count
153
+ yield
154
+ old_count != current.error_count
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+
162
+ end
data/lib/rapid/core.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'yaml'
2
+ require 'erubis'
3
+ require 'active_support/core_ext/string'
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
+ require 'active_model'
6
+
7
+ require "rapid/version"
8
+ require "rapid/error"
9
+ require "rapid/module"
10
+
11
+ require "rapid/settings"
12
+ require "rapid/check"
13
+
14
+ require "rapid/skeleton/helpers/directory"
15
+ require "rapid/skeleton/helpers/gem"
16
+ require "rapid/skeleton/helpers/migration"
17
+ require "rapid/skeleton/helpers/route"
18
+ require "rapid/skeleton/helpers/script"
19
+ require "rapid/skeleton/helpers/template"
20
+ require "rapid/skeleton/helpers/view"
21
+ require "rapid/skeleton/base"
22
+
23
+ require "rapid/template/base"
24
+ require "rapid/template/parser"
25
+
26
+ require "rapid/template/pulling/base"
27
+ require "rapid/template/pulling/explicit"
28
+ require "rapid/template/pulling/forgiving"
29
+
30
+ require "rapid/template/node/base"
31
+ require "rapid/template/node/root"
32
+ require "rapid/template/node/static"
33
+ require "rapid/template/node/variable"
34
+ require "rapid/template/node/if_node"
35
+ require "rapid/template/node/comment_node"
36
+
37
+ require 'rapid/railtie' if defined? Rails
@@ -0,0 +1,84 @@
1
+ module Rapid
2
+
3
+ class Exception < ::Exception ; end
4
+
5
+ class SettingError < Exception ; end
6
+ class SettingLoadError < Exception ; end
7
+ class InvalidYamlError < SettingLoadError ; end
8
+
9
+ class UnknownSettingError < SettingLoadError
10
+ attr_reader :setting_name
11
+
12
+ def initialize full_setting_name
13
+ @setting_name = full_setting_name
14
+ super "Can't find #{full_setting_name.inspect} setting"
15
+ end
16
+
17
+ def validation_message
18
+ "can't be found"
19
+ end
20
+
21
+ end
22
+
23
+ class InvalidSettingError < SettingLoadError
24
+ attr_reader :setting, :value
25
+
26
+ def initialize setting, value
27
+ @setting = setting
28
+ @value = value
29
+ super "Can't assign #{value.inspect} to #{setting.full_name}"
30
+ end
31
+
32
+ def validation_message
33
+ "doesn't allow values of that type"
34
+ end
35
+
36
+ end
37
+
38
+ class SkeletonError < Exception ; end
39
+ class InvalidSkeletonError < SkeletonError ; end
40
+
41
+ class TemplateError < Exception ; end
42
+ class InvalidTemplateError < TemplateError ; end
43
+ class NotMatchingTemplateError < TemplateError ; end
44
+ class TemplateNotFoundError < TemplateError ; end
45
+ class UnknownMethodTemplateError < TemplateError ; end
46
+
47
+ class NotMatchingTemplateError < TemplateError
48
+
49
+ attr_reader :result, :expected_content, :content, :previous_content
50
+
51
+ def initialize result, expected_content, content, options = {}
52
+ @result, @expected_content, @content = result, expected_content, content
53
+ @previous_content = options[:previous]
54
+ end
55
+
56
+ def message
57
+ messages = [
58
+ "after: #{previous_content.nil? ? "nil" : previous_content[0..100].inspect}",
59
+ "expected: #{expected_content[0..100].inspect}",
60
+ "received: #{content[0..100].inspect}",
61
+ "current: #{result.inspect}"
62
+ ]
63
+
64
+ messages.join("\n")
65
+ end
66
+
67
+ end
68
+
69
+ class TemplateRenderError < TemplateError
70
+
71
+ attr_reader :template_path, :original_exception
72
+
73
+ def initialize template_path, e
74
+ super "Error rendering #{template_path}: #{e.message}"
75
+ @template_path = template_path
76
+ @original_exception = e
77
+ end
78
+
79
+ end
80
+
81
+ class CheckError < Exception ; end
82
+ class FileNotFoundCheckError < CheckError ; end
83
+
84
+ end
@@ -0,0 +1,35 @@
1
+ module Rapid
2
+
3
+ class << self
4
+
5
+ attr_accessor :view_path
6
+
7
+ # from rspec
8
+
9
+ def colorize(text, color_code)
10
+ "#{color_code}#{text}\e[0m"
11
+ end
12
+
13
+ def red(text); colorize(text, "\e[31m"); end
14
+ def green(text); colorize(text, "\e[32m"); end
15
+ def yellow(text); colorize(text, "\e[33m"); end
16
+
17
+ def color_puts type, message
18
+ case type
19
+ when :ok
20
+ puts green(message)
21
+
22
+ when :warning
23
+ puts yellow(message)
24
+
25
+ when :error
26
+ puts red(message)
27
+
28
+ else
29
+ raise "Invalid type: #{type.inspect}"
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,18 @@
1
+ module Rapid
2
+
3
+ class Railtie < Rails::Railtie
4
+
5
+ rake_tasks do
6
+ load "rapid/tasks.rb"
7
+ end
8
+
9
+ initializer "rapid.view_paths" do
10
+ Rapid.view_path ||= File.join 'lib', 'rapid', 'views'
11
+
12
+ ActionController::Base.append_view_path Rapid.view_path
13
+ ActionMailer::Base.append_view_path Rapid.view_path
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,35 @@
1
+ module Rapid
2
+ module Setting
3
+
4
+ class Base
5
+
6
+ attr_reader :namespace, :full_name, :name, :default_value
7
+
8
+ def initialize name, options = {}
9
+ @name = name.to_sym
10
+ @namespace = options[:namespace]
11
+ @default_value = options[:default]
12
+ @full_name = @namespace ? "#{@namespace.full_name}.#{name}" : name.to_s
13
+
14
+ if Rapid::Settings.reserved_name? @name
15
+ raise ArgumentError.new("#{@name} is a reserved setting name")
16
+ end
17
+ end
18
+
19
+ def load value
20
+ raise "Subclass should override this method"
21
+ end
22
+
23
+ def get_helper_name
24
+ name
25
+ end
26
+
27
+ def set_helper_name
28
+ "#{name}="
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,17 @@
1
+ module Rapid
2
+ module Setting
3
+
4
+ class BooleanSetting < Base
5
+
6
+ def load value
7
+ if [0, "0", false, "false"].include?(value)
8
+ false
9
+ elsif [1, "1", true, "true"].include?(value)
10
+ true
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ module Rapid
2
+ module Setting
3
+
4
+ class ClassHash
5
+
6
+ attr_reader :delegate
7
+
8
+ delegate :[], :to => :delegate
9
+ delegate :[]=, :to => :delegate
10
+ delegate :empty?, :to => :delegate
11
+ delegate :each, :to => :delegate
12
+ delegate :keys, :to => :delegate
13
+ delegate :values, :to => :delegate
14
+ delegate :to_hash, :to => :delegate
15
+
16
+ def initialize
17
+ @delegate = HashWithIndifferentAccess.new
18
+ end
19
+
20
+ def namespaces
21
+ values = self.values.delete_if {|v| not v.is_a? Namespace::Base }
22
+ values
23
+ end
24
+
25
+ def scalars
26
+ values = self.values.delete_if {|v| v.is_a? Namespace::Base }
27
+ values
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,25 @@
1
+ module Rapid
2
+ module Setting
3
+
4
+ module Comments
5
+
6
+ def comment_unless boolean
7
+ if boolean
8
+ nil
9
+ else
10
+ "# "
11
+ end
12
+ end
13
+
14
+ def comment_if boolean
15
+ if boolean
16
+ "# "
17
+ else
18
+ nil
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,151 @@
1
+ module Rapid
2
+ module Setting
3
+
4
+ class Definer
5
+
6
+ def initialize klass, options = {}
7
+ @klass = klass
8
+ @delimiter = '.'
9
+ end
10
+
11
+ def boolean full_name, options = {}
12
+ namespace, name = find_namespace_and_name full_name
13
+ setting = BooleanSetting.new name, options.merge(:namespace => namespace)
14
+ define_setting setting
15
+ end
16
+
17
+ def string full_name, options = {}
18
+ namespace, name = find_namespace_and_name full_name
19
+ setting = StringSetting.new name, options.merge(:namespace => namespace)
20
+ define_setting setting
21
+ end
22
+
23
+ def integer full_name, options = {}
24
+ namespace, name = find_namespace_and_name full_name
25
+ setting = IntegerSetting.new name, options.merge(:namespace => namespace)
26
+ define_setting setting
27
+ end
28
+
29
+ def namespace full_name, options = {}
30
+ namespace, name = find_namespace_and_name full_name
31
+ setting = Namespace::Base.new name, options.merge(:namespace => namespace, :class => @klass)
32
+ define_setting setting
33
+ end
34
+
35
+ def code full_name, options = {}
36
+ namespace, name = find_namespace_and_name full_name
37
+ setting = StringSetting.new name, options.merge(:namespace => namespace)
38
+ define_setting setting
39
+ end
40
+
41
+ def class_eval namespace_name, &block
42
+ names = namespace_name.to_s.split('.')
43
+ namespace = find_namespace *names
44
+ raise ArgumentError.new("namespace not found: #{namespace_name.inspect}") unless namespace
45
+ raise ArgumentError.new("namespace does not have a custom class") unless namespace.instance_class
46
+ namespace.instance_class.class_eval &block
47
+ end
48
+
49
+ def find_namespace *names
50
+ namespace = nil
51
+ names.each_with_index do |name, index|
52
+ if index == 0
53
+ namespace = @klass.settings[name]
54
+ else
55
+ namespace = namespace[name]
56
+ end
57
+ end
58
+ namespace
59
+ end
60
+
61
+ def inspect
62
+ %(#<Rapid::Setting::Definer>)
63
+ end
64
+
65
+ protected
66
+
67
+ def find_or_create_namespace *names
68
+ namespace = nil
69
+
70
+ names.each_with_index do |name, index|
71
+ if index == 0
72
+ new_namespace = @klass.settings[name]
73
+ else
74
+ new_namespace = namespace[name]
75
+ end
76
+
77
+ if new_namespace.nil?
78
+ new_namespace = Namespace::Base.new name, :namespace => namespace, :class => @klass
79
+ define_setting new_namespace
80
+ end
81
+
82
+ namespace = new_namespace
83
+ end
84
+
85
+ namespace
86
+ end
87
+
88
+ def find_namespace_and_name full_name
89
+ names = full_name.to_s.split(@delimiter)
90
+ setting_name = names.pop.to_sym
91
+
92
+ namespace = find_or_create_namespace *names
93
+ return namespace, setting_name
94
+ end
95
+
96
+ def define_setting setting
97
+ if setting.namespace.nil?
98
+ define_base_setting setting
99
+ else
100
+ setting.namespace.define_setting setting
101
+ end
102
+
103
+ setting
104
+ end
105
+
106
+ def define_base_setting setting
107
+ define_methods setting
108
+ push_setting setting
109
+ end
110
+
111
+ def define_methods setting
112
+ name = setting.name
113
+ getter = setting.get_helper_name
114
+ setter = setting.set_helper_name
115
+
116
+ @klass.class_eval do
117
+ define_method getter do
118
+ settings[name]
119
+ end
120
+
121
+ define_method setter do |value|
122
+ settings[name] = value
123
+ end
124
+
125
+ if setting.is_a? BooleanSetting
126
+ define_method "#{getter}?" do
127
+ settings[name] == true
128
+ end
129
+ elsif setting.is_a? Namespace::Base
130
+ define_method "#{getter}?" do
131
+ settings[name] != nil && !settings[name].empty?
132
+ end
133
+ else
134
+ define_method "#{getter}?" do
135
+ settings[name] != nil
136
+ end
137
+ end
138
+ end
139
+
140
+ true
141
+ end
142
+
143
+ def push_setting setting
144
+ @klass.settings[setting.name] = setting
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+
151
+ end