silicon 0.2.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 (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