silicon 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) 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 +372 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +7 -0
  10. data/bin/setup +8 -0
  11. data/exe/silicon +5 -0
  12. data/lib/silicon.rb +6 -0
  13. data/lib/silicon/app.rb +90 -0
  14. data/lib/silicon/base/handle_errors.rb +16 -0
  15. data/lib/silicon/chain.rb +69 -0
  16. data/lib/silicon/chain_factory.rb +39 -0
  17. data/lib/silicon/config.rb +15 -0
  18. data/lib/silicon/errors/silicon_error.rb +4 -0
  19. data/lib/silicon/errors/syntax_error.rb +6 -0
  20. data/lib/silicon/errors/view_engine_error.rb +6 -0
  21. data/lib/silicon/extensions/hash.rb +18 -0
  22. data/lib/silicon/generators/cli.rb +23 -0
  23. data/lib/silicon/generators/templates/actions/common/handle_errors.rb +2 -0
  24. data/lib/silicon/generators/templates/actions/welcome.tt +9 -0
  25. data/lib/silicon/generators/templates/app.rb +4 -0
  26. data/lib/silicon/generators/templates/app.routes +4 -0
  27. data/lib/silicon/generators/templates/config.ru +8 -0
  28. data/lib/silicon/generators/templates/silicon.yml +7 -0
  29. data/lib/silicon/generators/templates/views/show_welcome.json.jbuilder +1 -0
  30. data/lib/silicon/loaders/dependency_loader.rb +14 -0
  31. data/lib/silicon/loaders/template_loader.rb +20 -0
  32. data/lib/silicon/loaders/type_loader.rb +25 -0
  33. data/lib/silicon/request.rb +65 -0
  34. data/lib/silicon/routing/builder.rb +96 -0
  35. data/lib/silicon/routing/file_reader.rb +27 -0
  36. data/lib/silicon/routing/match.rb +12 -0
  37. data/lib/silicon/routing/matcher.rb +40 -0
  38. data/lib/silicon/routing/parser.rb +25 -0
  39. data/lib/silicon/routing/route.rb +19 -0
  40. data/lib/silicon/routing/routing.rb +11 -0
  41. data/lib/silicon/routing/syntax.rb +28 -0
  42. data/lib/silicon/routing/syntax/action.rb +30 -0
  43. data/lib/silicon/routing/syntax/actions.rb +15 -0
  44. data/lib/silicon/routing/syntax/after_section.rb +19 -0
  45. data/lib/silicon/routing/syntax/before_section.rb +18 -0
  46. data/lib/silicon/routing/syntax/catch_section.rb +15 -0
  47. data/lib/silicon/routing/syntax/command.rb +27 -0
  48. data/lib/silicon/routing/syntax/commands.rb +7 -0
  49. data/lib/silicon/routing/syntax/node.rb +47 -0
  50. data/lib/silicon/routing/syntax/nodes.rb +13 -0
  51. data/lib/silicon/routing/syntax/primitives/arrow.rb +4 -0
  52. data/lib/silicon/routing/syntax/primitives/back_arrow.rb +4 -0
  53. data/lib/silicon/routing/syntax/primitives/eol.rb +4 -0
  54. data/lib/silicon/routing/syntax/primitives/http_status.rb +13 -0
  55. data/lib/silicon/routing/syntax/primitives/http_verb.rb +4 -0
  56. data/lib/silicon/routing/syntax/primitives/indent.rb +4 -0
  57. data/lib/silicon/routing/syntax/primitives/parameter.rb +4 -0
  58. data/lib/silicon/routing/syntax/primitives/path.rb +5 -0
  59. data/lib/silicon/routing/syntax/respond.rb +25 -0
  60. data/lib/silicon/routing/syntax/route.rb +25 -0
  61. data/lib/silicon/routing/syntax/sections.rb +19 -0
  62. data/lib/silicon/routing/syntax/tree_section.rb +11 -0
  63. data/lib/silicon/routing/syntax/view.rb +7 -0
  64. data/lib/silicon/routing/syntax_error_interpreter.rb +28 -0
  65. data/lib/silicon/routing/syntax_grammar.tt +95 -0
  66. data/lib/silicon/template_registry.rb +17 -0
  67. data/lib/silicon/version.rb +3 -0
  68. data/lib/silicon/view_builder.rb +18 -0
  69. data/lib/silicon/view_builder_registry.rb +21 -0
  70. data/lib/silicon/view_builders/json.rb +16 -0
  71. data/lib/silicon/view_factory.rb +21 -0
  72. data/silicon.gemspec +45 -0
  73. metadata +272 -0
@@ -0,0 +1,65 @@
1
+ require 'silicon/chain_factory'
2
+ require 'silicon/view_factory'
3
+
4
+ module Silicon
5
+ class Request
6
+ include Hypo::Scope
7
+
8
+ def initialize(route_matcher, container, chain_factory, view_factory)
9
+ @container = container
10
+ @route_matcher = route_matcher
11
+ @chain_factory = chain_factory
12
+ @view_factory = view_factory
13
+ end
14
+
15
+ def handle(rack_env)
16
+ create_scope
17
+
18
+ path = rack_env['PATH_INFO']
19
+ request_method = rack_env['REQUEST_METHOD']
20
+ match = @route_matcher.match(path, request_method)
21
+ content_type = rack_env['CONTENT_TYPE'] || 'application/json'
22
+
23
+ if match.nil?
24
+ result = [404, { 'Content-Type' => content_type }, []]
25
+ else
26
+ query = Rack::Utils.parse_nested_query(rack_env['QUERY_STRING']).symbolize_keys
27
+ register_params(query, :silicon_query)
28
+
29
+ data = rack_env['rack.parser.result']
30
+ register_params(data, :silicon_data)
31
+
32
+ chain = @chain_factory.create(match)
33
+ chain.execute
34
+
35
+ body = ''
36
+ if match.route.view
37
+ body = @view_factory.create(match.route.view, content_type)
38
+ end
39
+
40
+ status = @container.resolve(:silicon_status)
41
+ result = [status, { 'Content-Type' => content_type }, [body]]
42
+ end
43
+
44
+ release
45
+
46
+ result
47
+ end
48
+
49
+ private
50
+ def create_scope
51
+ @container
52
+ .register_instance(self, :silicon_request)
53
+ .using_lifetime(:scope)
54
+ .bound_to(self)
55
+ end
56
+
57
+ def register_params(params, name)
58
+ unless params.nil?
59
+ @container.register_instance(params, name)
60
+ .using_lifetime(:scope)
61
+ .bound_to(:silicon_request)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,96 @@
1
+ require 'silicon/routing/route'
2
+
3
+ module Silicon
4
+ module Routing
5
+ class Builder
6
+ def initialize
7
+ @parsed_items = []
8
+ @route_params = []
9
+ @current_parent = nil
10
+ @prev_route = nil
11
+ end
12
+
13
+ def build(sections)
14
+ result = []
15
+
16
+ node = sections.node
17
+ restore_hierarchy(node, nil,node.to_hash)
18
+
19
+ @route_params.each do |route|
20
+ if route[:actions]
21
+ route[:actions].each do |action|
22
+ result << Route.new({
23
+ path: restore_path(route).gsub('$', '/$'),
24
+ params: restore_params(route).map{|p| p.sub('$', '')},
25
+ http_verb: action[:http_verb],
26
+ view: action[:view],
27
+ http_status: action[:http_status],
28
+ catch: sections.catch.command,
29
+ commands: restore_callbacks(route, :before) + action[:commands] + restore_callbacks(route, :after)
30
+ })
31
+ end
32
+ end
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ private
39
+
40
+ def restore_hierarchy(node, prev_route, current_parent)
41
+ route = node.to_hash
42
+
43
+ if route[:level] == current_parent[:level]
44
+ route[:parent] = current_parent[:parent]
45
+ parent = route
46
+ elsif route[:level] > prev_route[:level]
47
+ route[:parent] = prev_route
48
+ parent = prev_route
49
+ else
50
+ route[:parent] = current_parent
51
+ parent = current_parent
52
+ end
53
+
54
+ @route_params << route
55
+ @prev_route = route
56
+
57
+ if node.my_nodes
58
+ node.my_nodes.each {|n| restore_hierarchy(n, route, parent)}
59
+ end
60
+ end
61
+
62
+ def restore_path(route)
63
+ path = (route[:route][:path] || route[:route][:parameter] || '')
64
+ if route[:parent]
65
+ restore_path(route[:parent]) + path
66
+ else
67
+ path
68
+ end
69
+ end
70
+
71
+ def restore_params(route)
72
+ if route[:route][:parameter]
73
+ param = [route[:route][:parameter]]
74
+ else
75
+ param = []
76
+ end
77
+
78
+ if route[:parent]
79
+ restore_params(route[:parent]) + param
80
+ else
81
+ param
82
+ end
83
+ end
84
+
85
+ def restore_callbacks(route, type)
86
+ before = route[type]
87
+
88
+ if route[:parent]
89
+ restore_callbacks(route[:parent], type) + before
90
+ else
91
+ before
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,27 @@
1
+ module Silicon
2
+ module Routing
3
+ class FileReader
4
+ def initialize(silicon_config)
5
+ @config = silicon_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 Silicon
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 'silicon/routing/match'
2
+
3
+ module Silicon
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('/')
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 Silicon
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 Silicon::SyntaxError, error_message
19
+ end
20
+
21
+ @routes_builder.build(tree.parse)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Silicon
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
+ @path = hash[:path].sub('.', '')
10
+ @params = hash[:params]
11
+ @commands = hash[:commands]
12
+ @view = hash[:view]
13
+ @http_status = hash[:http_status]
14
+ @segments = @path.split('/')
15
+ @catch = hash[:catch]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ require 'treetop'
2
+ require 'silicon/routing/builder'
3
+ require 'silicon/routing/parser'
4
+ require 'silicon/routing/matcher'
5
+ require 'silicon/routing/file_reader'
6
+ require 'silicon/routing/syntax_error_interpreter'
7
+ require 'silicon/routing/syntax_grammar'
8
+ require 'silicon/routing/syntax'
9
+
10
+ module Routing
11
+ end
@@ -0,0 +1,28 @@
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
+
10
+ require_relative 'syntax/action'
11
+ require_relative 'syntax/actions'
12
+ require_relative 'syntax/command'
13
+ require_relative 'syntax/commands'
14
+ require_relative 'syntax/view'
15
+ require_relative 'syntax/node'
16
+ require_relative 'syntax/nodes'
17
+ require_relative 'syntax/route'
18
+ require_relative 'syntax/respond'
19
+
20
+
21
+ require_relative 'syntax/sections'
22
+ require_relative 'syntax/before_section'
23
+ require_relative 'syntax/tree_section'
24
+ require_relative 'syntax/after_section'
25
+ require_relative 'syntax/catch_section'
26
+
27
+ module Syntax
28
+ 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,27 @@
1
+ module Syntax
2
+ class Command < Treetop::Runtime::SyntaxNode
3
+ attr_reader :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
+ @name = text_value.sub('*>', '').sub('=*', '').sub('=>', '')
11
+
12
+ self
13
+ end
14
+
15
+ def async?
16
+ @is_async
17
+ end
18
+
19
+ def parallel?
20
+ @is_parallel
21
+ end
22
+
23
+ def sequential?
24
+ @is_sequential
25
+ end
26
+ end
27
+ end