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,104 @@
1
+ module Rapid
2
+ module Spec
3
+
4
+ module Template
5
+
6
+ def self.included base
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ def templates_path
11
+ @templates_path
12
+ end
13
+
14
+ def template_path
15
+ @template_path
16
+ end
17
+
18
+ def template_name
19
+ @template_name
20
+ end
21
+
22
+ def template_content
23
+ File.open(template_path) {|f| f.read } if template_path
24
+ end
25
+
26
+ def push settings_hash = nil
27
+ if respond_to? :build_skeleton
28
+ @skeleton = build_skeleton
29
+
30
+ elsif Rapid::Spec::Template.skeleton_class
31
+ skeleton_class = Rapid::Spec::Template.skeleton_class
32
+ @skeleton = skeleton_class.new
33
+
34
+ else
35
+ raise "please set define build_skeleton or set Rapid::Spec::Template.skeleton_class before running specs"
36
+ end
37
+
38
+ @skeleton.load_hash settings_hash if settings_hash
39
+ @template = Rapid::Template::Base.new template_content
40
+ @result = @template.push @skeleton
41
+ end
42
+
43
+ def pull content = {}
44
+ # render with the settings
45
+ if content.is_a? Hash
46
+ content = push content
47
+ end
48
+
49
+ @content = content
50
+ @template = Rapid::Template::Base.new template_content
51
+ @result = @template.pull @content
52
+ end
53
+
54
+ module ClassMethods
55
+
56
+ def template_spec filename
57
+ templates_path, template_path, template_name = Rapid::Spec::Template.find filename
58
+
59
+ before do
60
+ @templates_path = templates_path
61
+ @template_path = template_path
62
+ @template_name = template_name
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ class << self
70
+ attr_accessor :skeleton_class
71
+
72
+ def find filename
73
+ if filename =~ /\/spec\//
74
+ templates_path = File.join $`, 'templates'
75
+ end
76
+
77
+ raise "Templates path could not found be: #{filename.inspect}" unless templates_path
78
+
79
+ if filename =~ /\/templates\/(.+)_spec.rb$/
80
+ template_name = $1
81
+ template_path = File.join templates_path, template_name
82
+
83
+ unless File.exists?(template_path) && !File.directory?(template_path)
84
+ template_name += ".rb"
85
+ template_path = File.join templates_path, template_name
86
+
87
+ unless File.exists?(template_path)
88
+ raise "Couldn't figure out the template file location for: #{filename.inspect}"
89
+ end
90
+ end
91
+
92
+ else
93
+ raise "Not sure where the template file is for #{filename.inspect}"
94
+ end
95
+
96
+ return templates_path, template_path, template_name
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
data/lib/rapid/spec.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rapid/spec/template'
@@ -0,0 +1,29 @@
1
+ namespace :rapid do
2
+
3
+ desc "Checks that none of your rapid skeletons are violated"
4
+ task :check => :environment do
5
+ start_time = Time.now
6
+ @check = Rapid::Check.new_with_detection :console => true
7
+
8
+ is_valid = @check.valid?
9
+
10
+ end_time = Time.now
11
+
12
+ puts "\nFinished in #{end_time - start_time} seconds"
13
+
14
+ results = []
15
+ results << "#{@check.check_count} checks"
16
+ results << "#{@check.warning_count} warnings" if @check.warning_count > 0
17
+ results << "#{@check.error_count} errors"
18
+
19
+ output = results.join(', ') << "\n"
20
+
21
+ if is_valid
22
+ Rapid.color_puts :ok, output
23
+ else
24
+ Rapid.color_puts :error, output
25
+ fail "Rapid check found some errors"
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,49 @@
1
+ module Rapid
2
+ module Template
3
+
4
+ class Base
5
+
6
+ attr_reader :content, :filename
7
+
8
+ def initialize content, options = {}
9
+ @content = polish_content content
10
+ @filename = options[:filename]
11
+
12
+ @erb = Erubis::Eruby.new @content
13
+ end
14
+
15
+ def push skeleton
16
+ @erb.result skeleton.get_binding
17
+ rescue Exception, SyntaxError, NameError => e
18
+ raise TemplateRenderError.new(@filename, e)
19
+ end
20
+
21
+ def pull content
22
+ content = polish_content content
23
+
24
+ nodes = Parser.new(@content).parse
25
+
26
+ result = Pulling::Forgiving.new(content)
27
+ nodes.pull result
28
+
29
+ result.empty!
30
+ result.to_hash
31
+ end
32
+
33
+ protected
34
+
35
+ def polish_content content
36
+ content
37
+ # if content.ends_with? "\n\n"
38
+ # $`
39
+ # elsif content.ends_with? "\n"
40
+ # $`
41
+ # else
42
+ # content
43
+ # end
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ module Rapid
2
+ module Template
3
+ module Node
4
+
5
+ class Base
6
+
7
+ attr_reader :parent
8
+
9
+ def initialize
10
+
11
+ end
12
+
13
+ def pull result
14
+ raise NotImplementedError.new("pull not implemented for #{self.class}")
15
+ end
16
+
17
+ def next_to child
18
+ # subclasses fill this in
19
+ end
20
+
21
+ def next_node
22
+ parent.next_to self if parent
23
+ end
24
+
25
+ def static?
26
+ is_a? Static
27
+ end
28
+
29
+ def content
30
+
31
+ end
32
+
33
+ protected
34
+
35
+ def parent= parent
36
+ @parent = parent
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ module Rapid
2
+ module Template
3
+ module Node
4
+
5
+ class CommentNode < Base
6
+
7
+ attr_reader :value, :variable
8
+
9
+ def initialize value, variable
10
+ @value = value
11
+ @variable = variable
12
+
13
+ if @variable.ends_with? "?"
14
+ @variable = @variable[0..-2]
15
+ end
16
+ end
17
+
18
+ def pull result
19
+ len = result.starts_with "# "
20
+ if len
21
+ result.move! len
22
+ result[variable] = value
23
+ else
24
+ result[variable] = !value
25
+ end
26
+ end
27
+
28
+ def == obj
29
+ obj.is_a?(self.class) &&
30
+ obj.variable == variable &&
31
+ obj.value == value
32
+ end
33
+
34
+ def inspect
35
+ %(#<comment @value=#{@value.inspect} @variable=#{@variable.inspect}>)
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,109 @@
1
+ module Rapid
2
+ module Template
3
+ module Node
4
+
5
+ class IfNode < Base
6
+
7
+ attr_reader :statement, :then_node, :else_node
8
+
9
+ def initialize statement, then_nodes, else_nodes = nil
10
+ @statement = statement
11
+
12
+ @then_node = polish_nodes then_nodes
13
+ @else_node = polish_nodes else_nodes
14
+
15
+ @then_node.send :parent=, self if @then_node
16
+ @else_node.send :parent=, self if @else_node
17
+ end
18
+
19
+ def pull result
20
+ then_content = then_node.content if then_node
21
+ if then_content.nil?
22
+ raise Rapid::InvalidTemplateError.new("if statement must have content within it")
23
+ end
24
+
25
+ if result.starts_with? then_content
26
+ then_node.pull result
27
+ pull_variable result, statement, true
28
+ else
29
+ pull_variable result, statement, false
30
+ else_node.pull result if else_node
31
+ end
32
+ end
33
+
34
+ def next_to node
35
+ parent.next_to self if parent
36
+ end
37
+
38
+ def == obj
39
+ obj.is_a?(self.class) &&
40
+ obj.statement == statement &&
41
+ obj.then_node == then_node &&
42
+ obj.else_node == @else_node
43
+ end
44
+
45
+ def inspect
46
+ %(#<if @statement=#{@statement.inspect} @then=#{@then_node.inspect} @else=#{@else_node.inspect}>)
47
+ end
48
+
49
+ protected
50
+
51
+ def pull_variable result, statement, is_success
52
+ if statement =~ /^[a-z][A-Za-z0-9\_\.]*$/
53
+ result[statement] = is_success unless result.key? statement
54
+
55
+ elsif statement =~ /^[a-z][A-Za-z0-9\_\.]*\?$/
56
+ name = statement[0..-2]
57
+ result[name] = is_success unless result.key? name
58
+
59
+ elsif statement =~ /^([a-z][A-Za-z0-9\_\.]*) == true$/
60
+ result[$1] = is_success
61
+
62
+ elsif statement =~ /^([a-z][A-Za-z0-9\_\.]*) == false$/
63
+ result[$1] = !is_success
64
+
65
+ elsif is_success
66
+
67
+ if statement =~ /^([a-z][A-Za-z0-9\_\.]*) == \"([^\"]*)\"$/
68
+ result[$1] = $2
69
+
70
+ elsif statement =~ /^([a-z][A-Za-z0-9\_\.]*) == \'([^\"]*)\'$/
71
+ result[$1] = $2
72
+
73
+ elsif statement =~ /^([a-z][A-Za-z0-9\_\.]*) == ([0-9]+)$/
74
+ result[$1] = $2.to_i
75
+
76
+ elsif statement =~ /^([a-z][A-Za-z0-9\_\.]*) == ([0-9]+\.[0-9]+)$/
77
+ result[$1] = $2.to_f
78
+
79
+ else
80
+ raise Rapid::InvalidTemplateError.new("unknown if statement #{statement.inspect}")
81
+ end
82
+
83
+ end
84
+ end
85
+
86
+ def polish_nodes nodes
87
+ if nodes.is_a?(Array)
88
+ if nodes.length == 1
89
+ nodes.first
90
+ else
91
+ Root.new nodes
92
+ end
93
+
94
+ elsif nodes.is_a? Base
95
+ nodes
96
+
97
+ elsif nodes.nil?
98
+ nil
99
+
100
+ else
101
+ raise ArgumentError.new("unknown type: #{nodes.class}")
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,51 @@
1
+ module Rapid
2
+ module Template
3
+ module Node
4
+
5
+ class Root < Base
6
+
7
+ attr_reader :nodes
8
+
9
+ def initialize nodes
10
+ @nodes = nodes
11
+
12
+ nodes.each do |n|
13
+ n.send :parent=, self
14
+ end
15
+ end
16
+
17
+ def next_to node
18
+ # OPTIMIZE need object level eql? this the best way?
19
+ index = nil
20
+ nodes.each_with_index {|n, i| index = i if node.eql? n }
21
+ return unless index
22
+
23
+ node = nodes[index+1]
24
+ return node if node
25
+
26
+ parent.next_node if parent
27
+ end
28
+
29
+ def pull result
30
+ @nodes.each do |node|
31
+ node.pull result
32
+ end
33
+ end
34
+
35
+ def content
36
+ nodes.first.content if nodes.first
37
+ end
38
+
39
+ def == obj
40
+ obj.is_a?(self.class) && obj.nodes == @nodes
41
+ end
42
+
43
+ def inspect
44
+ %(#<root nodes=#{@nodes.inspect}>)
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,29 @@
1
+ module Rapid
2
+ module Template
3
+ module Node
4
+
5
+ class Static < Base
6
+
7
+ attr_accessor :content
8
+
9
+ def initialize content
10
+ @content = content
11
+ end
12
+
13
+ def pull result
14
+ result.match! @content
15
+ end
16
+
17
+ def == obj
18
+ obj.is_a?(self.class) && obj.content == @content
19
+ end
20
+
21
+ def inspect
22
+ %(#<static #{@content.inspect}>)
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,86 @@
1
+ module Rapid
2
+ module Template
3
+ module Node
4
+
5
+ class Variable < Base
6
+
7
+ attr_reader :name
8
+
9
+ def initialize name
10
+ if name.blank?
11
+ raise Rapid::InvalidTemplateError.new("Empty ERB statements aren't allowed")
12
+ end
13
+
14
+ @name = name
15
+ end
16
+
17
+ def pull result
18
+ next_piece = next_node
19
+ if next_piece.nil?
20
+ result[name] = result.content.clone
21
+ result.move! result.content.length
22
+ return
23
+ end
24
+
25
+ unless next_piece.static?
26
+ raise Rapid::InvalidTemplateError.new("Two ERB variables can't be touching #{result.content[0..20].inspect}")
27
+ end
28
+
29
+ index = result.index next_piece.content
30
+ if index.nil?
31
+ next_piece_does_not_match result, next_piece.content
32
+ end
33
+
34
+ if index == 0
35
+ value = ""
36
+ else
37
+ value = result.content[0..index-1]
38
+ result.move! index
39
+ end
40
+
41
+ result[name] = value
42
+ end
43
+
44
+ def == obj
45
+ obj.is_a?(self.class) && obj.name == @name
46
+ end
47
+
48
+ def inspect
49
+ %(#<variable #{@name.inspect}>)
50
+ end
51
+
52
+ protected
53
+
54
+ def next_piece_does_not_match result, content
55
+ # try and match the variable before throwing the error because it's
56
+ # likely the error isn't on the variable, but the text following the variable
57
+ if content.length > 20
58
+ start = content[0..20]
59
+ index = result.index start
60
+
61
+ if index.nil?
62
+ # do nothing
63
+
64
+ elsif index == 0
65
+ value = ""
66
+ else
67
+ value = result.content[0..index-1]
68
+ result.move! index
69
+ end
70
+
71
+ result[name] = value if value
72
+
73
+ success, result_match, content_match = result.match content
74
+ result.move! result_match if result_match > 0
75
+
76
+ content = content[content_match..-1] if content_match > 0
77
+ end
78
+
79
+ result.raise_not_matching content
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+ end
86
+ end