dandy 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +134 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +7 -0
  10. data/bin/setup +8 -0
  11. data/dandy.gemspec +46 -0
  12. data/exe/dandy +5 -0
  13. data/lib/dandy.rb +6 -0
  14. data/lib/dandy/app.rb +93 -0
  15. data/lib/dandy/base/handle_errors.rb +16 -0
  16. data/lib/dandy/chain.rb +68 -0
  17. data/lib/dandy/chain_factory.rb +39 -0
  18. data/lib/dandy/config.rb +15 -0
  19. data/lib/dandy/errors/dandy_error.rb +4 -0
  20. data/lib/dandy/errors/syntax_error.rb +6 -0
  21. data/lib/dandy/errors/view_engine_error.rb +6 -0
  22. data/lib/dandy/extensions/hash.rb +18 -0
  23. data/lib/dandy/generators/cli.rb +58 -0
  24. data/lib/dandy/generators/templates/Gemfile +4 -0
  25. data/lib/dandy/generators/templates/actions/common/handle_errors.rb +2 -0
  26. data/lib/dandy/generators/templates/actions/welcome.tt +9 -0
  27. data/lib/dandy/generators/templates/app/app.rb +4 -0
  28. data/lib/dandy/generators/templates/app/app.routes +4 -0
  29. data/lib/dandy/generators/templates/config.ru +17 -0
  30. data/lib/dandy/generators/templates/silicon.yml +7 -0
  31. data/lib/dandy/generators/templates/views/show_welcome.json.jbuilder +1 -0
  32. data/lib/dandy/loaders/dependency_loader.rb +21 -0
  33. data/lib/dandy/loaders/template_loader.rb +20 -0
  34. data/lib/dandy/loaders/type_loader.rb +25 -0
  35. data/lib/dandy/request.rb +65 -0
  36. data/lib/dandy/routing/builder.rb +96 -0
  37. data/lib/dandy/routing/file_reader.rb +27 -0
  38. data/lib/dandy/routing/match.rb +12 -0
  39. data/lib/dandy/routing/matcher.rb +40 -0
  40. data/lib/dandy/routing/parser.rb +25 -0
  41. data/lib/dandy/routing/route.rb +23 -0
  42. data/lib/dandy/routing/routing.rb +11 -0
  43. data/lib/dandy/routing/syntax.rb +29 -0
  44. data/lib/dandy/routing/syntax/action.rb +30 -0
  45. data/lib/dandy/routing/syntax/actions.rb +15 -0
  46. data/lib/dandy/routing/syntax/after_section.rb +19 -0
  47. data/lib/dandy/routing/syntax/before_section.rb +18 -0
  48. data/lib/dandy/routing/syntax/catch_section.rb +15 -0
  49. data/lib/dandy/routing/syntax/command.rb +36 -0
  50. data/lib/dandy/routing/syntax/commands.rb +7 -0
  51. data/lib/dandy/routing/syntax/node.rb +47 -0
  52. data/lib/dandy/routing/syntax/nodes.rb +13 -0
  53. data/lib/dandy/routing/syntax/primitives/arrow.rb +4 -0
  54. data/lib/dandy/routing/syntax/primitives/back_arrow.rb +4 -0
  55. data/lib/dandy/routing/syntax/primitives/eol.rb +4 -0
  56. data/lib/dandy/routing/syntax/primitives/http_status.rb +13 -0
  57. data/lib/dandy/routing/syntax/primitives/http_verb.rb +4 -0
  58. data/lib/dandy/routing/syntax/primitives/indent.rb +4 -0
  59. data/lib/dandy/routing/syntax/primitives/parameter.rb +4 -0
  60. data/lib/dandy/routing/syntax/primitives/path.rb +5 -0
  61. data/lib/dandy/routing/syntax/primitives/result_name.rb +4 -0
  62. data/lib/dandy/routing/syntax/respond.rb +25 -0
  63. data/lib/dandy/routing/syntax/route.rb +25 -0
  64. data/lib/dandy/routing/syntax/sections.rb +19 -0
  65. data/lib/dandy/routing/syntax/tree_section.rb +11 -0
  66. data/lib/dandy/routing/syntax/view.rb +7 -0
  67. data/lib/dandy/routing/syntax_error_interpreter.rb +28 -0
  68. data/lib/dandy/routing/syntax_grammar.tt +99 -0
  69. data/lib/dandy/template_registry.rb +29 -0
  70. data/lib/dandy/version.rb +3 -0
  71. data/lib/dandy/view_builder.rb +18 -0
  72. data/lib/dandy/view_builder_registry.rb +21 -0
  73. data/lib/dandy/view_builders/json.rb +16 -0
  74. data/lib/dandy/view_factory.rb +21 -0
  75. metadata +288 -0
@@ -0,0 +1,27 @@
1
+ module Dandy
2
+ module Routing
3
+ class FileReader
4
+ def initialize(dandy_config)
5
+ @config = dandy_config
6
+ end
7
+
8
+ def read
9
+ path = File.join('./', @config[:path][:routes])
10
+ content = File.read(path)
11
+
12
+ # use '^' instead spaces and tabs
13
+ raw_content = content.gsub(/\t/, ' ')
14
+ .gsub(' ', '^')
15
+ .gsub(' ', '')
16
+
17
+ ###Hack:
18
+ # grammar problem - can't simply match '-' character in route path when '->' present.
19
+ # Will be resolved later. Replace '->', '<-' with '*>', '<*' for a while for syntax parser.
20
+ ###
21
+ raw_content = raw_content.gsub('->', '*>').gsub('<-', '<*')
22
+
23
+ raw_content.gsub!("\n", ';') + ';'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ module Dandy
2
+ module Routing
3
+ class Match
4
+ attr_reader :route, :params
5
+
6
+ def initialize(route, params)
7
+ @route = route
8
+ @params = params
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,40 @@
1
+ require 'dandy/routing/match'
2
+
3
+ module Dandy
4
+ module Routing
5
+ class Matcher
6
+ def initialize(routes)
7
+ @routes = routes
8
+ end
9
+
10
+ def match(path, http_method)
11
+ segments = path.split('/').concat(['/'])
12
+ params = {}
13
+ matched = nil
14
+
15
+ @routes.each do |route|
16
+ if route.segments.length == segments.length
17
+ for i in 0..segments.length - 1 do
18
+ template = route.segments[i]
19
+ value = segments[i]
20
+
21
+ if value == template
22
+ elsif template.index('$') == 0
23
+ name = template.sub('$', '')
24
+ params[name] = value
25
+ else
26
+ break
27
+ end
28
+
29
+ if i == segments.length - 1 && route.http_verb == http_method
30
+ matched = route
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ matched.nil? ? nil : Match.new(matched, params)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ module Dandy
2
+ module Routing
3
+ class Parser
4
+ def initialize(file_reader, routes_builder,
5
+ syntax_parser, syntax_error_interpreter)
6
+ @file_reader = file_reader
7
+ @routes_builder = routes_builder
8
+ @syntax_parser = syntax_parser
9
+ @syntax_error_interpreter = syntax_error_interpreter
10
+ end
11
+
12
+ def parse
13
+ content = @file_reader.read
14
+ tree = @syntax_parser.parse(content)
15
+
16
+ if tree.nil?
17
+ error_message = @syntax_error_interpreter.interpret
18
+ raise Dandy::SyntaxError, error_message
19
+ end
20
+
21
+ @routes_builder.build(tree.parse)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ module Dandy
2
+ module Routing
3
+ class Route
4
+ attr_reader :http_verb, :path, :params, :catch,
5
+ :commands, :segments, :view, :http_status
6
+
7
+ def initialize(hash)
8
+ @http_verb = hash[:http_verb]
9
+
10
+ @path = hash[:path].sub('.', '/').sub('//', '/')
11
+
12
+ @params = hash[:params]
13
+ @commands = hash[:commands]
14
+ @view = hash[:view]
15
+ @http_status = hash[:http_status]
16
+
17
+ @segments = @path.split('/').concat(['/'])
18
+
19
+ @catch = hash[:catch]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ require 'treetop'
2
+ require 'dandy/routing/builder'
3
+ require 'dandy/routing/parser'
4
+ require 'dandy/routing/matcher'
5
+ require 'dandy/routing/file_reader'
6
+ require 'dandy/routing/syntax_error_interpreter'
7
+ require 'dandy/routing/syntax_grammar'
8
+ require 'dandy/routing/syntax'
9
+
10
+ module Routing
11
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'syntax/primitives/arrow'
2
+ require_relative 'syntax/primitives/back_arrow'
3
+ require_relative 'syntax/primitives/eol'
4
+ require_relative 'syntax/primitives/indent'
5
+ require_relative 'syntax/primitives/http_verb'
6
+ require_relative 'syntax/primitives/http_status'
7
+ require_relative 'syntax/primitives/parameter'
8
+ require_relative 'syntax/primitives/path'
9
+ require_relative 'syntax/primitives/result_name'
10
+
11
+ require_relative 'syntax/action'
12
+ require_relative 'syntax/actions'
13
+ require_relative 'syntax/command'
14
+ require_relative 'syntax/commands'
15
+ require_relative 'syntax/view'
16
+ require_relative 'syntax/node'
17
+ require_relative 'syntax/nodes'
18
+ require_relative 'syntax/route'
19
+ require_relative 'syntax/respond'
20
+
21
+
22
+ require_relative 'syntax/sections'
23
+ require_relative 'syntax/before_section'
24
+ require_relative 'syntax/tree_section'
25
+ require_relative 'syntax/after_section'
26
+ require_relative 'syntax/catch_section'
27
+
28
+ module Syntax
29
+ end
@@ -0,0 +1,30 @@
1
+ module Syntax
2
+ class Action < Treetop::Runtime::SyntaxNode
3
+ attr_reader :http_verb, :commands, :node, :respond
4
+
5
+ def parse(node)
6
+ @node = node
7
+ @commands = []
8
+
9
+ elements.each do |element|
10
+ if element.is_a? HttpVerb
11
+ @http_verb = element.text_value
12
+ end
13
+
14
+ if element.is_a? Commands
15
+ @commands = element.parse
16
+ end
17
+
18
+ if element.is_a? Respond
19
+ @respond = element.parse
20
+ end
21
+ end
22
+
23
+ self
24
+ end
25
+
26
+ def to_hash
27
+ {http_verb: @http_verb, commands: @commands, view: @respond.view, http_status: @respond.http_status}
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module Syntax
2
+ class Actions < Treetop::Runtime::SyntaxNode
3
+ attr_reader :actions
4
+
5
+ def parse(node)
6
+ @actions = []
7
+
8
+ elements.each do |element|
9
+ @actions << element.parse(node).to_hash
10
+ end
11
+
12
+ @actions
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module Syntax
2
+ class AfterSection < Treetop::Runtime::SyntaxNode
3
+ attr_reader :commands
4
+
5
+ def parse
6
+ @commands = []
7
+
8
+ if elements.length > 0
9
+ elements[0].elements.each do |element|
10
+ if element.is_a? Commands
11
+ @commands = element.parse
12
+ end
13
+ end
14
+ end
15
+
16
+ self
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ module Syntax
2
+ class BeforeSection < Treetop::Runtime::SyntaxNode
3
+ attr_reader :commands
4
+
5
+ def parse
6
+ @commands = []
7
+ if elements.length > 0
8
+ elements[0].elements.each do |element|
9
+ if element.is_a? Commands
10
+ @commands = element.parse
11
+ end
12
+ end
13
+ end
14
+
15
+ self
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ module Syntax
2
+ class CatchSection < Treetop::Runtime::SyntaxNode
3
+ attr_reader :command
4
+
5
+ def parse
6
+ elements[0].elements.each do |element|
7
+ if element.is_a? Command
8
+ @command = element.parse
9
+ end
10
+ end
11
+
12
+ self
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ module Syntax
2
+ class Command < Treetop::Runtime::SyntaxNode
3
+ attr_reader :name, :result_name
4
+
5
+ def parse
6
+ @is_async = text_value.start_with? '=*'
7
+ @is_parallel = text_value.start_with? '=>'
8
+ @is_sequential = text_value.start_with? '*>'
9
+
10
+ full_name = text_value.sub('*>', '').sub('=*', '').sub('=>', '')
11
+
12
+ if full_name.include? '@'
13
+ parts = full_name.split('@')
14
+ @result_name = parts[0]
15
+ @name = parts[1]
16
+ else
17
+ @result_name = "#{full_name}_result"
18
+ @name = full_name
19
+ end
20
+
21
+ self
22
+ end
23
+
24
+ def async?
25
+ @is_async
26
+ end
27
+
28
+ def parallel?
29
+ @is_parallel
30
+ end
31
+
32
+ def sequential?
33
+ @is_sequential
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+ module Syntax
2
+ class Commands < Treetop::Runtime::SyntaxNode
3
+ def parse
4
+ elements.map {|element| element.parse}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,47 @@
1
+ module Syntax
2
+ class Node < Treetop::Runtime::SyntaxNode
3
+ attr_accessor :route, :actions, :my_nodes, :parent_node, :level, :before_commands, :after_commands
4
+
5
+ def parse(parent_node = nil)
6
+ @parent_node = parent_node
7
+
8
+ elements.each do |element|
9
+ if element.is_a? Indent
10
+ @level = element.elements.length
11
+ end
12
+
13
+ if element.is_a? Route
14
+ @route = element.parse(self)
15
+ end
16
+
17
+ if element.is_a? Actions
18
+ @actions = element.parse(self)
19
+ end
20
+
21
+ if element.is_a? Nodes
22
+ @my_nodes = element.parse(self)
23
+ end
24
+
25
+ if element.is_a? BeforeSection
26
+ @before_commands = element.parse.commands
27
+ end
28
+
29
+ if element.is_a? AfterSection
30
+ @after_commands = element.parse.commands
31
+ end
32
+ end
33
+
34
+ self
35
+ end
36
+
37
+ def to_hash
38
+ {
39
+ route: @route.to_hash,
40
+ actions: @actions,
41
+ level: @level,
42
+ before: @before_commands,
43
+ after: @after_commands
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ module Syntax
2
+ class Nodes < Treetop::Runtime::SyntaxNode
3
+ def parse(node)
4
+ nodes = []
5
+
6
+ elements.each do |element|
7
+ nodes << element.parse(node)
8
+ end
9
+
10
+ nodes
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module Syntax
2
+ class Arrow < Treetop::Runtime::SyntaxNode
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Syntax
2
+ class BackArrow < Treetop::Runtime::SyntaxNode
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Syntax
2
+ class Eol < Treetop::Runtime::SyntaxNode
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ module Syntax
2
+ class HttpStatus < Treetop::Runtime::SyntaxNode
3
+ def parse
4
+ result = nil
5
+
6
+ unless text_value.empty?
7
+ result = text_value.sub('=', '').to_i
8
+ end
9
+
10
+ result
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module Syntax
2
+ class HttpVerb < Treetop::Runtime::SyntaxNode
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Syntax
2
+ class Indent < Treetop::Runtime::SyntaxNode
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Syntax
2
+ class Parameter < Treetop::Runtime::SyntaxNode
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Syntax
2
+ class Path < Treetop::Runtime::SyntaxNode
3
+
4
+ end
5
+ end