dandy 0.6.0

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 (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