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,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
@@ -0,0 +1,25 @@
1
+ module Syntax
2
+ class Respond < Treetop::Runtime::SyntaxNode
3
+ attr_reader :view, :http_status
4
+
5
+ def parse
6
+ if elements.length > 0
7
+ elements[0].elements[1].elements.each do |element|
8
+ if element.is_a? View
9
+ @view = element.parse
10
+ end
11
+
12
+ if element.is_a? HttpStatus
13
+ @http_status = element.parse
14
+ end
15
+ end
16
+ end
17
+
18
+ self
19
+ end
20
+
21
+ def to_hash
22
+ {view: @view, http_status: @http_status}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module Syntax
2
+ class Route < Treetop::Runtime::SyntaxNode
3
+ attr_reader :node, :path, :parameter
4
+
5
+ def parse(node)
6
+ @node = node
7
+
8
+ elements.each do |element|
9
+ if element.is_a? Parameter
10
+ @parameter = element.text_value
11
+ end
12
+
13
+ if element.is_a? Path
14
+ @path = element.text_value
15
+ end
16
+ end
17
+
18
+ self
19
+ end
20
+
21
+ def to_hash
22
+ {path: @path, parameter: @parameter}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Syntax
2
+ class Sections < Treetop::Runtime::SyntaxNode
3
+ attr_reader :node, :catch
4
+
5
+ def parse
6
+ elements.each do |element|
7
+ if element.is_a? Node
8
+ @node = element.parse
9
+ end
10
+
11
+ if element.is_a? CatchSection
12
+ @catch = element.parse
13
+ end
14
+ end
15
+
16
+ self
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Syntax
2
+ class TreeSection < Treetop::Runtime::SyntaxNode
3
+ attr_reader :node
4
+
5
+ def parse
6
+ @node = elements[2].parse
7
+
8
+ self
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module Syntax
2
+ class View < Treetop::Runtime::SyntaxNode
3
+ def parse
4
+ text_value.sub('<*', '')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ require 'silicon/errors/syntax_error'
2
+
3
+ module Silicon
4
+ module Routing
5
+ class SyntaxErrorInterpreter
6
+ def initialize(syntax_parser)
7
+ @syntax_parser = syntax_parser
8
+ end
9
+
10
+ def interpret
11
+ line_num = 1
12
+ (0..@syntax_parser.max_terminal_failure_index - 1).each {|i|
13
+ line_num += 1 if @syntax_parser.input[i] == ';'
14
+ }
15
+
16
+ message = "Syntax error in routes definition, line #{line_num}. Expected: "
17
+ expected = []
18
+ @syntax_parser.terminal_failures.each do |f|
19
+ item = f.expected_string
20
+ .gsub('^', '<space>/<tab>')
21
+ .gsub(';', '<new line>')
22
+ expected << item
23
+ end
24
+ message + expected.join(', ') + '.'
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,95 @@
1
+ grammar Syntax
2
+ rule sections
3
+ ':receive' eol node catch <Sections>
4
+ end
5
+
6
+ rule before
7
+ (indent ':before' commands eol+) 0..1 <BeforeSection>
8
+ end
9
+
10
+ rule after
11
+ (indent ':after' commands eol+) 0..1 <AfterSection>
12
+ end
13
+
14
+ rule catch
15
+ (':catch' command eol*) 0..1 <CatchSection>
16
+ end
17
+
18
+ rule node
19
+ indent route before after actions nodes <Node>
20
+ end
21
+
22
+ rule action
23
+ indent http_verb commands respond eol <Action>
24
+ end
25
+
26
+ rule route
27
+ (path / parameter) arrow eol <Route>
28
+ end
29
+
30
+ rule path
31
+ ('.' / ('/' [a-z0-9_\-]+)) 1..1 <Path>
32
+ end
33
+
34
+ rule http_verb
35
+ ('GET' / 'POST' / 'PUT' / 'PATCH' / 'DELETE') 1..1 <HttpVerb>
36
+ end
37
+
38
+ rule parameter
39
+ ('$' [a-z0-9_]+) 1..1 <Parameter>
40
+ end
41
+
42
+ rule command
43
+ (arrow [a-z0-9_]+) 1..1 <Command>
44
+ end
45
+
46
+ rule commands
47
+ command+ <Commands>
48
+ end
49
+
50
+ rule actions
51
+ action* <Actions>
52
+ end
53
+
54
+ rule nodes
55
+ node* <Nodes>
56
+ end
57
+
58
+ rule view
59
+ (back_arrow [a-z] [a-z0-9_]* ('/' [a-z0-9_]*)*) 0..1 <View>
60
+ end
61
+
62
+ rule respond
63
+ (arrow (':respond' view http_status)) 0..1 <Respond>
64
+ end
65
+
66
+ rule http_status
67
+ ('=' (
68
+ '100' / '101' / '102' /
69
+ '200' / '201' / '202' / '203' / '204' / '205' / '206' / '207' / '208' / '226' /
70
+ '300' / '301' / '302' / '303' / '304' / '305' / '306' / '307' / '308' /
71
+ '400' / '401' / '402' / '403' / '404' / '405' / '406' / '407' / '408' /
72
+ '409' / '410' / '411' / '412' / '413' / '414' / '415' / '416' / '417' / '418' /
73
+ '421' / '422' / '423' / '424' / '426' / '428' / '429' / '431' / '444' / '449' / '451' /
74
+ '500' / '501' / '502' / '503' / '504' / '505' / '506' / '507' / '508' /
75
+ '509' / '510' / '511' / '520' / '521' / '522' / '523' / '524' / '525' / '526'
76
+ ) 1..1) 0..1
77
+ <HttpStatus>
78
+ end
79
+
80
+ rule arrow
81
+ ('*>' / '=>' / '=*') 1..1 <Arrow>
82
+ end
83
+
84
+ rule back_arrow
85
+ '<*' <BackArrow>
86
+ end
87
+
88
+ rule eol
89
+ ';'+ <Eol>
90
+ end
91
+
92
+ rule indent
93
+ '^'+ <Indent>
94
+ end
95
+ end
@@ -0,0 +1,17 @@
1
+ module Silicon
2
+ class TemplateRegistry
3
+ def initialize(template_loader, silicon_config)
4
+ @templates = template_loader.load_templates
5
+ @config = silicon_config
6
+ end
7
+
8
+ def get(name, type)
9
+ directory = @config[:path][:views]
10
+ template_path = File.join(directory, name + ".#{type}")
11
+ match = @templates.keys.find{|k| k.include? template_path}
12
+ raise Silicon::SiliconError, "View #{name} of type #{type} not found" if match.nil?
13
+
14
+ @templates[match]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module Silicon
2
+ VERSION = '0.2.0'.freeze
3
+ end
@@ -0,0 +1,18 @@
1
+ module Silicon
2
+ class ViewBuilder
3
+ def initialize(template, container)
4
+ @template = template
5
+ @container = container
6
+ @variables = template.scan(/@[a-z_][a-zA-Z_0-9]*/).uniq
7
+ end
8
+
9
+ def process
10
+ @variables.each do |variable|
11
+ value = @container.resolve(variable.sub('@', '').to_sym)
12
+ instance_variable_set variable, value
13
+ end
14
+
15
+ build
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'silicon/view_builder'
2
+
3
+ module Silicon
4
+ class ViewBuilderRegistry
5
+ def initialize
6
+ @view_builders = {}
7
+ end
8
+
9
+ def add(view_builder, format)
10
+ unless view_builder < Silicon::ViewBuilder
11
+ raise Silicon::SiliconError, 'view_builder parameter should be a Silicon::ViewBuilder'
12
+ end
13
+
14
+ @view_builders[format] = view_builder
15
+ end
16
+
17
+ def get(format)
18
+ @view_builders[format]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require 'jbuilder'
2
+ require 'silicon/view_builder'
3
+
4
+ module Silicon
5
+ module ViewBuilders
6
+ class Json < Silicon::ViewBuilder
7
+ def build
8
+ result = Jbuilder.new do |json|
9
+ eval(@template)
10
+ end
11
+
12
+ result.target!
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'silicon/template_registry'
2
+ require 'silicon/view_builders/json'
3
+ require 'silicon/view_builder_registry'
4
+
5
+ module Silicon
6
+ class ViewFactory
7
+ def initialize(container, template_registry, view_builder_registry)
8
+ @container = container
9
+ @template_registry = template_registry
10
+ @view_builder_registry = view_builder_registry
11
+ end
12
+
13
+ def create(name, content_type)
14
+ type = content_type.split('/')[1]
15
+ template = @template_registry.get(name, type)
16
+ builder = @view_builder_registry.get(type)
17
+ view = builder.new(template, @container)
18
+ view.process
19
+ end
20
+ end
21
+ end