c66-copper 0.0.1

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +5 -0
  3. data/bin/console +14 -0
  4. data/bin/copper +96 -0
  5. data/bin/setup +8 -0
  6. data/lib/copper/action.rb +9 -0
  7. data/lib/copper/attribute.rb +30 -0
  8. data/lib/copper/attribute_params.rb +9 -0
  9. data/lib/copper/attributes.rb +21 -0
  10. data/lib/copper/attributes_right_associated.rb +11 -0
  11. data/lib/copper/boolean.rb +9 -0
  12. data/lib/copper/comparison.rb +58 -0
  13. data/lib/copper/compop.rb +8 -0
  14. data/lib/copper/copper.rb +32 -0
  15. data/lib/copper/copper_node.rb +16 -0
  16. data/lib/copper/data_types/array.rb +61 -0
  17. data/lib/copper/data_types/data_type.rb +54 -0
  18. data/lib/copper/data_types/ip_addr.rb +82 -0
  19. data/lib/copper/data_types/range.rb +17 -0
  20. data/lib/copper/data_types/semver.rb +45 -0
  21. data/lib/copper/data_types/string.rb +23 -0
  22. data/lib/copper/error.rb +5 -0
  23. data/lib/copper/expression.rb +8 -0
  24. data/lib/copper/expression_utils.rb +13 -0
  25. data/lib/copper/functions/fetch.rb +27 -0
  26. data/lib/copper/functions/ip_address.rb +18 -0
  27. data/lib/copper/grammar/copper.treetop +161 -0
  28. data/lib/copper/identifier.rb +9 -0
  29. data/lib/copper/loader.rb +13 -0
  30. data/lib/copper/logic.rb +14 -0
  31. data/lib/copper/logic_op.rb +7 -0
  32. data/lib/copper/logic_right_associated.rb +16 -0
  33. data/lib/copper/number.rb +10 -0
  34. data/lib/copper/param.rb +13 -0
  35. data/lib/copper/param_right_associated.rb +10 -0
  36. data/lib/copper/parser.rb +42 -0
  37. data/lib/copper/range.rb +15 -0
  38. data/lib/copper/root.rb +13 -0
  39. data/lib/copper/rule_definition.rb +21 -0
  40. data/lib/copper/set.rb +11 -0
  41. data/lib/copper/single_var_definition.rb +20 -0
  42. data/lib/copper/string.rb +17 -0
  43. data/lib/copper/var_definition.rb +11 -0
  44. data/lib/copper/variable.rb +9 -0
  45. data/lib/copper/variable_identifier.rb +15 -0
  46. data/lib/copper/version.rb +5 -0
  47. data/lib/copper.rb +5 -0
  48. metadata +247 -0
@@ -0,0 +1,27 @@
1
+ require 'jsonpath'
2
+
3
+ module Copper
4
+ module Functions
5
+ class Fetch < CopperNode
6
+
7
+ include ::Copper::ExpressionUtils
8
+
9
+ def value(vars = {})
10
+ key = elements[0].value(vars)
11
+ context = vars[:context]
12
+
13
+ begin
14
+ path = JsonPath.new(key)
15
+ result = path.on(context)
16
+ rescue ArgumentError => exc
17
+ raise ParseError, "JSONPath error #{key}: #{exc.message}"
18
+ rescue NoMethodError => exc
19
+ raise ParseError, "JSONPath error #{key}. Invalid JSONPath"
20
+ end
21
+
22
+ return handle_attributes(result, vars)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ require 'ipaddress'
2
+
3
+ module Copper
4
+ module Functions
5
+ class IPAddress < CopperNode
6
+
7
+ include ::Copper::ExpressionUtils
8
+
9
+ def value(vars = {})
10
+ ipaddress = elements[0].value(vars)
11
+ result = ::IPAddress.parse(ipaddress)
12
+
13
+ return handle_attributes(result, vars)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,161 @@
1
+ grammar Copper
2
+
3
+ rule root
4
+ (var_definition / rule_definition / comment / comment_block)+ <Root>
5
+ end
6
+
7
+ rule comment
8
+ s '//' (![\n\r] .)* [\n\r]
9
+ end
10
+
11
+ rule comment_block
12
+ s '/*' (!'*/' .)* '*/' s
13
+ end
14
+
15
+ rule rule_definition
16
+ s 'rule' s identifier s action s '{' sn
17
+ logic sn
18
+ '}' sn
19
+ <RuleDefinition>
20
+ end
21
+
22
+ rule var_definition
23
+ s 'var' s single_var_definition
24
+ <VarDefinition>
25
+ end
26
+
27
+ rule single_var_definition
28
+ s identifier s '=' s expression sn <SingleVarDefinition>
29
+ end
30
+
31
+ rule logic
32
+ s comparison s (logic_right_associated)? sn <Logic>
33
+ end
34
+
35
+ rule range
36
+ s '(' s expression s '..' s expression s ')' (attributes)? <Range>
37
+ end
38
+
39
+ rule expression
40
+ s (string / number / boolean / func / variable / set / range) <Expression>
41
+ end
42
+
43
+ rule logic_right_associated
44
+ logic_op sn logic <LogicRightAssociated>
45
+ end
46
+
47
+ rule action
48
+ 'ensure' <Action>
49
+ / 'warn' <Action>
50
+ end
51
+
52
+ rule logic_op
53
+ 'and' <LogicOp>
54
+ / '&' <LogicOp>
55
+ / '&&' <LogicOp>
56
+ / 'or' <LogicOp>
57
+ / '|' <LogicOp>
58
+ / '||' <LogicOp>
59
+ / '->' <CompOp>
60
+ end
61
+
62
+ rule comparison
63
+ s expression s comp_op s expression <Comparison>
64
+ / s boolean <Boolean>
65
+ end
66
+
67
+ rule func
68
+ (fetch_func / func_ipaddress)
69
+ end
70
+
71
+ rule fetch_func
72
+ 'fetch' s '(' s (string / variable) s ')' (attributes)? <Functions::Fetch>
73
+ end
74
+
75
+ rule func_ipaddress
76
+ 'ipaddress' s '(' (string / variable) s ')' (attributes)? <Functions::IPAddress>
77
+ end
78
+
79
+ rule attributes
80
+ sn '.' attribute (attributes_right_associated)? <Attributes>
81
+ end
82
+
83
+ rule attributes_right_associated
84
+ (attributes) <AttributesRightAssociated>
85
+ end
86
+
87
+ rule attribute
88
+ identifier attribute_params? <Attribute>
89
+ end
90
+
91
+ rule params
92
+ s expression s (param_right_associated)? <Param>
93
+ end
94
+
95
+ rule param_right_associated
96
+ ',' s params <ParamRightAssociated>
97
+ end
98
+
99
+ rule attribute_params
100
+ s '(' s (params) s ')' <AttributeParams>
101
+ end
102
+
103
+ rule set
104
+ s '[' (params) s ']' (attributes)? <Set>
105
+ end
106
+
107
+ rule variable_identifier
108
+ [a-zA-Z] [a-zA-Z0-9_]* <VariableIdentifier>
109
+ end
110
+
111
+ rule variable
112
+ variable_identifier (attributes)? <Variable>
113
+ end
114
+
115
+ rule identifier
116
+ [a-zA-Z] [a-zA-Z0-9_]* <Identifier>
117
+ end
118
+
119
+ rule number
120
+ [0-9]+ <Number>
121
+ end
122
+
123
+ rule comp_op
124
+ '<=' <CompOp>
125
+ / '>=' <CompOp>
126
+ / '<' <CompOp>
127
+ / '>' <CompOp>
128
+ / '==' <CompOp>
129
+ / '=' <CompOp>
130
+ / '!=' <CompOp>
131
+ / 'in' <CompOp>
132
+ / '->' <CompOp>
133
+ end
134
+
135
+ rule boolean
136
+ 'true' <Boolean>
137
+ / 'false' <Boolean>
138
+ / 'console' <Boolean>
139
+ end
140
+
141
+ rule string
142
+ '"' string_content '"' (attributes)? <String>
143
+ end
144
+
145
+ rule string_content
146
+ ([^"\\] / "\\" . )* <StringContent>
147
+ end
148
+
149
+ rule sn
150
+ s '//' (![\n\r] .)* [\n\r] / s / s [\n\r] / [\n\r]
151
+ end
152
+
153
+ rule s
154
+ [\s\t]*
155
+ end
156
+
157
+ rule S
158
+ [\s\t]+
159
+ end
160
+
161
+ end
@@ -0,0 +1,9 @@
1
+ module Copper
2
+ # Node class for an identifier
3
+ class Identifier < CopperNode
4
+
5
+ def value(vars = {})
6
+ return self.text_value.to_sym
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ require 'treetop'
2
+
3
+ # Load the parser from the Treetop grammar.
4
+ Treetop.load(File.join(__dir__, 'grammar', 'copper.treetop'))
5
+
6
+ require File.join(__dir__, 'data_types', 'data_type')
7
+ # Load custom Copper syntax node.
8
+ require File.join(__dir__, 'copper_node')
9
+
10
+ require File.join(__dir__, 'expression_utils')
11
+
12
+ # Load other Copper classes.
13
+ Dir.glob File.join(__dir__, '**', '*.rb'), &method(:require)
@@ -0,0 +1,14 @@
1
+ module Copper
2
+ class Logic < CopperNode
3
+ def value(vars = {})
4
+ if elements[1].nil?
5
+ # no right association
6
+ return elements[0].value(vars)
7
+ else
8
+ # has right association
9
+ return elements[1].value(vars)
10
+ end
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,7 @@
1
+ module Copper
2
+ class LogicOp < CopperNode
3
+ def value(vars = {})
4
+ return text_value
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module Copper
2
+ class LogicRightAssociated < CopperNode
3
+ def value(vars = {})
4
+ rhs = self.parent.elements[0].value(vars)
5
+ op = self.elements[0].value(vars)
6
+ lhs = self.elements[1].value(vars)
7
+
8
+ case op
9
+ when 'and', '&', '&&'
10
+ return (lhs and rhs)
11
+ when 'or', '|', '||'
12
+ return (lhs or rhs)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module Copper
2
+ # Node class for a simple number.
3
+ class Number < CopperNode
4
+
5
+ def value(vars = {})
6
+ return text_value.to_i
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Copper
2
+ class Param < CopperNode
3
+ def value(vars = {})
4
+ if elements[1].nil?
5
+ # no right association
6
+ return elements[0].value(vars)
7
+ else
8
+ # has right association
9
+ return elements[1].value(vars)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Copper
2
+ class ParamRightAssociated < CopperNode
3
+ def value(vars = {})
4
+ rhs = self.parent.elements[0].value(vars)
5
+ lhs = self.elements[0].value(vars)
6
+
7
+ return ([rhs] + [lhs]).flatten
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module Copper
2
+ class Parser
3
+ def initialize
4
+ @parser = CopperParser.new
5
+ end
6
+
7
+ def parse(content)
8
+ root_node = @parser.parse(content)
9
+
10
+ # Raise any errors.
11
+ unless root_node
12
+ @parser.failure_reason =~ /^(Expected .+) after/m
13
+ if $1.nil?
14
+ puts "#{@parser.failure_reason}"
15
+ else
16
+ puts "#{$1.gsub("\n", '$NEWLINE')}:"
17
+ end
18
+ puts content.lines.to_a[@parser.failure_line - 1]
19
+ puts "#{'~' * (@parser.failure_column - 1)}^"
20
+ return nil
21
+ end
22
+
23
+ puts root_node.inspect if $parser_debug
24
+
25
+ clean_tree(root_node)
26
+
27
+ puts root_node.inspect if $parser_debug
28
+
29
+ root_node
30
+ end
31
+
32
+ def cc_parser
33
+ @parser
34
+ end
35
+
36
+ def clean_tree(root_node)
37
+ return if(root_node.elements.nil?)
38
+ root_node.elements.delete_if { |node| !node.is_a?(CopperNode) }
39
+ root_node.elements.each { |node| self.clean_tree(node) }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Copper
2
+ class Range < CopperNode
3
+
4
+ include ::Copper::ExpressionUtils
5
+
6
+ def value(vars = {})
7
+ lhs = elements[0].value(vars)
8
+ rhs = elements[1].value(vars)
9
+
10
+ return handle_attributes((lhs..rhs), vars)
11
+ rescue ArgumentError => exc
12
+ raise RuntimeError, "#{lhs} (#{lhs.class.name})..#{rhs} (#{rhs.class.name}) #{exc.message}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Copper
2
+ class Root < CopperNode
3
+ def value(vars = {})
4
+ result = []
5
+ elements.each do |element|
6
+ parse_result = element.value(vars)
7
+ result << parse_result unless parse_result.nil?
8
+ end
9
+
10
+ return result
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Copper
2
+ class RuleDefinition < CopperNode
3
+
4
+ def value(vars = {})
5
+ rules = vars[:rules] || []
6
+ t = {}
7
+ t[:name] = elements[0].value(vars)
8
+
9
+ raise ParseError, "a rule named #{t[:name]} already exists" if rules.detect { |x| x[:name] == t[:name] }
10
+
11
+ t[:outcome] = elements[2].value(vars)
12
+ t[:action] = elements[1].value(vars)
13
+
14
+ rules << t
15
+ vars[:rules] = rules
16
+
17
+ return t
18
+ end
19
+
20
+ end
21
+ end
data/lib/copper/set.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Copper
2
+ class Set < CopperNode
3
+
4
+ include ::Copper::ExpressionUtils
5
+
6
+ def value(vars = {})
7
+ return handle_attributes(elements[0].value(vars), vars)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module Copper
2
+ class SingleVarDefinition < CopperNode
3
+ RESERVED_VARS = [:semver, :array, :string]
4
+
5
+ def value(vars = {})
6
+ variables = vars[:variables] || {}
7
+
8
+ lhr = elements[0].value(vars)
9
+ rhs = elements[1].value(vars)
10
+
11
+ # check for resevered words
12
+ raise ::Copper::RuntimeError, "#{lhr} is a reserved word" if ::Copper::SingleVarDefinition::RESERVED_VARS.include?(lhr.to_sym)
13
+
14
+ variables[lhr.to_sym] = rhs
15
+ vars[:variables] = variables
16
+
17
+ return nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Copper
2
+ # Node class for a simple string.
3
+ class String < CopperNode
4
+
5
+ include ::Copper::ExpressionUtils
6
+
7
+ def value(vars = {})
8
+ return handle_attributes(elements[0].value(vars), vars)
9
+ end
10
+ end
11
+
12
+ class StringContent < CopperNode
13
+ def value(vars = {})
14
+ return text_value
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Copper
2
+ class VarDefinition < CopperNode
3
+ def value(vars = {})
4
+ elements.each do |element|
5
+ element.value(vars)
6
+ end
7
+
8
+ return nil
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Copper
2
+ class Variable < CopperNode
3
+ include ::Copper::ExpressionUtils
4
+
5
+ def value(vars = {})
6
+ return handle_attributes(elements[0].value(vars), vars)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module Copper
2
+ class VariableIdentifier < CopperNode
3
+
4
+ def value(vars = {})
5
+ variables = vars[:variables] || {}
6
+ identifier = self.text_value.to_sym
7
+ if variables.has_key?(identifier)
8
+ return variables[identifier]
9
+ else
10
+ raise ::Copper::ParseError, "no variable found with name #{identifier}"
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Copper
2
+ VERSION = '0.0.1'
3
+ COPYRIGHT_MESSAGE = "(c) 2018 Cloud66 Inc."
4
+ APP_NAME = 'Copper'
5
+ end
data/lib/copper.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'copper/version'
2
+ require_relative 'copper/loader'
3
+
4
+ module Copper
5
+ end