code-ruby 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +28 -55
  6. data/TODO +17 -0
  7. data/bin/code +56 -31
  8. data/bin/format +3 -0
  9. data/bin/template +62 -20
  10. data/bin/test +17 -0
  11. data/code-ruby.gemspec +1 -6
  12. data/docs/class.code +9 -0
  13. data/docs/euler/1.template +1 -5
  14. data/docs/euler/5.template +0 -1
  15. data/docs/meetup.code +12 -0
  16. data/docs/precedence.template +6 -39
  17. data/docs/rain.code +22 -0
  18. data/docs/slack.code +17 -0
  19. data/docs/stripe.code +7 -0
  20. data/docs/twitter.code +9 -0
  21. data/language-ruby.gemspec +18 -0
  22. data/lib/code/error.rb +3 -0
  23. data/lib/code/node/base_10.rb +29 -0
  24. data/lib/code/node/base_16.rb +13 -0
  25. data/lib/code/node/base_2.rb +13 -0
  26. data/lib/code/node/base_8.rb +13 -0
  27. data/lib/code/node/boolean.rb +7 -7
  28. data/lib/code/node/call.rb +32 -37
  29. data/lib/code/node/call_argument.rb +11 -27
  30. data/lib/code/node/chained_call.rb +10 -25
  31. data/lib/code/node/code.rb +4 -6
  32. data/lib/code/node/decimal.rb +26 -0
  33. data/lib/code/node/dictionnary.rb +20 -9
  34. data/lib/code/node/equal.rb +18 -20
  35. data/lib/code/node/function.rb +10 -7
  36. data/lib/code/node/function_parameter.rb +31 -0
  37. data/lib/code/node/if.rb +36 -32
  38. data/lib/code/node/if_modifier.rb +35 -36
  39. data/lib/code/node/list.rb +6 -9
  40. data/lib/code/node/negation.rb +5 -23
  41. data/lib/code/node/not.rb +15 -0
  42. data/lib/code/node/nothing.rb +1 -1
  43. data/lib/code/node/number.rb +14 -12
  44. data/lib/code/node/operation.rb +21 -16
  45. data/lib/code/node/power.rb +10 -6
  46. data/lib/code/node/rescue.rb +4 -3
  47. data/lib/code/node/splat.rb +15 -0
  48. data/lib/code/node/statement.rb +47 -69
  49. data/lib/code/node/string.rb +41 -10
  50. data/lib/code/node/ternary.rb +7 -9
  51. data/lib/code/node/unary_minus.rb +5 -12
  52. data/lib/code/node/while.rb +17 -24
  53. data/lib/code/node.rb +7 -8
  54. data/lib/code/object/argument.rb +3 -12
  55. data/lib/code/object/decimal.rb +114 -27
  56. data/lib/code/object/dictionnary.rb +29 -12
  57. data/lib/code/object/function.rb +23 -24
  58. data/lib/code/object/global.rb +42 -0
  59. data/lib/code/object/integer.rb +142 -35
  60. data/lib/code/object/list.rb +74 -95
  61. data/lib/code/object/range.rb +38 -50
  62. data/lib/code/object/ruby_function.rb +31 -0
  63. data/lib/code/object/string.rb +36 -16
  64. data/lib/code/object.rb +114 -54
  65. data/lib/code/parser/addition.rb +12 -20
  66. data/lib/code/parser/and_operator.rb +9 -20
  67. data/lib/code/parser/bitwise_and.rb +9 -20
  68. data/lib/code/parser/bitwise_or.rb +12 -20
  69. data/lib/code/parser/boolean.rb +10 -7
  70. data/lib/code/parser/call.rb +92 -60
  71. data/lib/code/parser/chained_call.rb +47 -0
  72. data/lib/code/parser/class.rb +45 -0
  73. data/lib/code/parser/code.rb +17 -10
  74. data/lib/code/parser/dictionnary.rb +56 -30
  75. data/lib/code/parser/equal.rb +87 -35
  76. data/lib/code/parser/equality.rb +23 -24
  77. data/lib/code/parser/equality_lower.rb +9 -0
  78. data/lib/code/parser/function.rb +67 -40
  79. data/lib/code/parser/greater.rb +25 -0
  80. data/lib/code/parser/group.rb +13 -8
  81. data/lib/code/parser/if.rb +51 -21
  82. data/lib/code/parser/if_modifier.rb +43 -16
  83. data/lib/code/parser/list.rb +32 -19
  84. data/lib/code/parser/multiplication.rb +15 -20
  85. data/lib/code/parser/name.rb +96 -84
  86. data/lib/code/parser/negation.rb +20 -9
  87. data/lib/code/parser/not_keyword.rb +14 -12
  88. data/lib/code/parser/nothing.rb +13 -8
  89. data/lib/code/parser/number.rb +124 -68
  90. data/lib/code/parser/operation.rb +35 -0
  91. data/lib/code/parser/or_keyword.rb +12 -20
  92. data/lib/code/parser/or_operator.rb +9 -20
  93. data/lib/code/parser/power.rb +32 -14
  94. data/lib/code/parser/range.rb +9 -17
  95. data/lib/code/parser/rescue.rb +29 -13
  96. data/lib/code/parser/shift.rb +11 -21
  97. data/lib/code/parser/splat.rb +31 -0
  98. data/lib/code/parser/statement.rb +4 -3
  99. data/lib/code/parser/string.rb +53 -62
  100. data/lib/code/parser/ternary.rb +36 -15
  101. data/lib/code/parser/unary_minus.rb +23 -5
  102. data/lib/code/parser/while.rb +26 -15
  103. data/lib/code/parser/whitespace.rb +49 -0
  104. data/lib/code/parser.rb +15 -0
  105. data/lib/code/ruby.rb +162 -0
  106. data/lib/code-ruby.rb +2 -5
  107. data/lib/code.rb +24 -7
  108. data/lib/language/atom.rb +343 -0
  109. data/lib/language/output.rb +130 -0
  110. data/lib/language/parser/absent/present.rb +8 -0
  111. data/lib/language/parser/absent.rb +6 -0
  112. data/lib/language/parser/end_of_input.rb +6 -0
  113. data/lib/language/parser/interuption.rb +38 -0
  114. data/lib/language/parser/not_end_of_input.rb +6 -0
  115. data/lib/language/parser/str/not_found.rb +16 -0
  116. data/lib/language/parser/str.rb +6 -0
  117. data/lib/language/parser.rb +53 -0
  118. data/lib/language-ruby.rb +10 -0
  119. data/lib/language.rb +80 -0
  120. data/lib/template/node/code_part.rb +1 -1
  121. data/lib/template/node/part.rb +1 -1
  122. data/lib/template/node/template.rb +1 -1
  123. data/lib/template/node/text_part.rb +1 -1
  124. data/lib/template/node.rb +1 -1
  125. data/lib/template/parser/template.rb +26 -17
  126. data/lib/template/parser.rb +15 -0
  127. data/lib/template/version.rb +1 -1
  128. data/lib/template-ruby.rb +2 -5
  129. data/lib/template.rb +23 -13
  130. data/spec/code/addition_spec.rb +13 -0
  131. data/spec/code/and_operator_spec.rb +13 -0
  132. data/spec/code/bitwise_and_spec.rb +13 -0
  133. data/spec/code/bitwise_or_spec.rb +13 -0
  134. data/spec/code/boolean_spec.rb +13 -0
  135. data/spec/code/call_spec.rb +21 -0
  136. data/spec/code/chained_call_spec.rb +16 -0
  137. data/spec/code/dictionnary_spec.rb +17 -0
  138. data/spec/code/equal_spec.rb +26 -0
  139. data/spec/code/equality_spec.rb +13 -0
  140. data/spec/code/function_spec.rb +18 -0
  141. data/spec/code/greater_spec.rb +18 -0
  142. data/spec/code/group_spec.rb +12 -0
  143. data/spec/code/if_modifier_spec.rb +20 -0
  144. data/spec/code/if_spec.rb +25 -0
  145. data/spec/code/list_spec.rb +17 -0
  146. data/spec/code/multiplication_spec.rb +18 -0
  147. data/spec/code/negation_spec.rb +20 -0
  148. data/spec/code/not_keyword_spec.rb +13 -0
  149. data/spec/code/nothing_spec.rb +17 -0
  150. data/spec/code/number_spec.rb +22 -0
  151. data/spec/code/or_keyword_spec.rb +17 -0
  152. data/spec/code/or_operator_spec.rb +16 -0
  153. data/spec/code/parser/boolean_spec.rb +5 -7
  154. data/spec/code/parser/call_spec.rb +16 -56
  155. data/spec/code/parser/chained_call.rb +17 -0
  156. data/spec/code/parser/dictionnary_spec.rb +8 -9
  157. data/spec/code/parser/function_spec.rb +5 -21
  158. data/spec/code/parser/group_spec.rb +18 -0
  159. data/spec/code/parser/list_spec.rb +9 -20
  160. data/spec/code/parser/number_spec.rb +4 -109
  161. data/spec/code/parser/string_spec.rb +9 -17
  162. data/spec/code/parser_spec.rb +23 -0
  163. data/spec/code/power_spec.rb +13 -0
  164. data/spec/code/range_spec.rb +16 -0
  165. data/spec/code/rescue_spec.rb +13 -0
  166. data/spec/code/shift_spec.rb +13 -0
  167. data/spec/code/splat_spec.rb +13 -0
  168. data/spec/code/string_spec.rb +25 -0
  169. data/spec/code/ternary_spec.rb +18 -0
  170. data/spec/code/unary_minus_spec.rb +13 -0
  171. data/spec/code/while_spec.rb +18 -0
  172. data/spec/spec_helper.rb +4 -1
  173. data/template-ruby.gemspec +2 -7
  174. metadata +113 -99
  175. data/lib/code/node/base_10_decimal.rb +0 -32
  176. data/lib/code/node/base_10_integer.rb +0 -32
  177. data/lib/code/node/base_10_number.rb +0 -19
  178. data/lib/code/node/base_16_number.rb +0 -19
  179. data/lib/code/node/base_2_number.rb +0 -19
  180. data/lib/code/node/base_8_number.rb +0 -19
  181. data/lib/code/node/block.rb +0 -17
  182. data/lib/code/node/defined.rb +0 -19
  183. data/lib/code/node/dictionnary_key_value.rb +0 -23
  184. data/lib/code/node/function_argument.rb +0 -45
  185. data/lib/code/node/group.rb +0 -13
  186. data/lib/code/node/keyword_call_argument.rb +0 -30
  187. data/lib/code/node/keyword_function_argument.rb +0 -33
  188. data/lib/code/node/name.rb +0 -55
  189. data/lib/code/node/not_keyword.rb +0 -13
  190. data/lib/code/node/or_keyword.rb +0 -34
  191. data/lib/code/node/range.rb +0 -31
  192. data/lib/code/node/regular_call_argument.rb +0 -34
  193. data/lib/code/node/regular_function_argument.rb +0 -36
  194. data/lib/code/node/string_characters.rb +0 -13
  195. data/lib/code/node/string_component.rb +0 -23
  196. data/lib/code/node/string_interpolation.rb +0 -13
  197. data/lib/code/parser/defined.rb +0 -20
  198. data/lib/code/parser/greater_than.rb +0 -33
  199. data/spec/call_spec.rb +0 -22
  200. data/spec/code/error/type_error_spec.rb +0 -63
  201. data/spec/code/parser/name_spec.rb +0 -15
  202. data/spec/code/parser/nothing_spec.rb +0 -19
  203. data/spec/code_spec.rb +0 -120
  204. data/spec/function_spec.rb +0 -26
  205. data/spec/template/parser/template_spec.rb +0 -19
  206. data/spec/template_spec.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dfeedb1e668e150c3039e1cee85eee9072ea16d0f619f45e71263c8c94ae707
4
- data.tar.gz: 1c2fb6de918462b02df14191ab14f7d27a92f0bea9113a54fa8344e7b8bab48e
3
+ metadata.gz: 0d3eab372ae2a63a19a9c6df1a8628d5dd27892de2c1976f067cf85e74b417a1
4
+ data.tar.gz: 9b0a7f5d97a9a076b711e7bf8872722d46a2906f98e988f9b661a150a5dcec00
5
5
  SHA512:
6
- metadata.gz: c810a7b5a9ca1cbfc9c710e1ec615dd043dccf047fd220f35b71cf8e7fa2feab9cbf3fde9b1f31b57c690e25f5be1e71f4881a0efced0baea0b9f51e4a9abd78
7
- data.tar.gz: 45571c9a8247d75f3c513e52dfebc4ed3e3fe527996c5a1dc8717fb740c6fa4736c6fb26da93c57a73558318f45a4bf5dc3d2ccf38b460d570b58d1171e8a776
6
+ metadata.gz: 72c41b22eaec2f7e43d7f9dd8355b2a797da3fc91fc82621328e2e0bad8fbe7edac71a2a2271559b09f9871cd4f8d20560ff92cdbc4f8d7cddc9882c15e32cff
7
+ data.tar.gz: 36e9c2247fa179763e091499d2c4315e45bb302308e7460ac4b9fca3513bfad0ae7bfe4fbf95ea2071295b3d892874bc5b26248a2f19762c3a3d6e66a0f48812
data/.gitignore CHANGED
@@ -1,2 +1,2 @@
1
1
  *.gem
2
- examples.txt
2
+ tmp/
data/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.4.0 / 2022-10-21
9
+
10
+ - Rewrite of how functions are called internally (no more `public_send`)
11
+ - Call ruby functions from template/code
12
+
8
13
  ## 0.3.1 / 2022-10-13
9
14
 
10
15
  - Fix Zeitwerk auto-loading issue
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec name: "template-ruby"
4
4
  gemspec name: "code-ruby"
5
+
6
+ gem "rspec"
7
+ gem "syntax_tree", github: "dorianmariefr/syntax_tree"
8
+ gem "ruby-prof"
data/Gemfile.lock CHANGED
@@ -1,74 +1,47 @@
1
+ GIT
2
+ remote: https://github.com/dorianmariefr/syntax_tree.git
3
+ revision: f7c9dc36a3d60c90a8d2411f123913b37319dc11
4
+ specs:
5
+ syntax_tree (5.0.1)
6
+ prettier_print (>= 1.1.0)
7
+
1
8
  PATH
2
9
  remote: .
3
10
  specs:
4
- code-ruby (0.2.4)
5
- activesupport (~> 7)
6
- parslet (~> 2)
7
- zeitwerk (~> 2.6)
8
- template-ruby (0.2.4)
9
- activesupport (~> 7)
10
- parslet (~> 2)
11
- zeitwerk (~> 2.6)
11
+ code-ruby (0.4.0)
12
+ zeitwerk (~> 2)
13
+ template-ruby (0.4.0)
14
+ zeitwerk (~> 2)
12
15
 
13
16
  GEM
14
17
  remote: https://rubygems.org/
15
18
  specs:
16
- activesupport (7.0.3.1)
17
- concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (>= 1.6, < 2)
19
- minitest (>= 5.1)
20
- tzinfo (~> 2.0)
21
- concurrent-ruby (1.1.10)
22
19
  diff-lcs (1.5.0)
23
- haml (5.2.2)
24
- temple (>= 0.8.0)
25
- tilt
26
- i18n (1.12.0)
27
- concurrent-ruby (~> 1.0)
28
- minitest (5.16.3)
29
- parslet (2.0.0)
30
- prettier (3.2.0)
31
- syntax_tree (>= 2.7.1)
32
- syntax_tree-haml (>= 1.1.0)
33
- syntax_tree-rbs (>= 0.2.0)
34
- prettier_print (0.1.0)
35
- rbs (2.6.0)
36
- rspec (3.11.0)
37
- rspec-core (~> 3.11.0)
38
- rspec-expectations (~> 3.11.0)
39
- rspec-mocks (~> 3.11.0)
40
- rspec-core (3.11.0)
41
- rspec-support (~> 3.11.0)
42
- rspec-expectations (3.11.0)
20
+ prettier_print (1.1.0)
21
+ rspec (3.12.0)
22
+ rspec-core (~> 3.12.0)
23
+ rspec-expectations (~> 3.12.0)
24
+ rspec-mocks (~> 3.12.0)
25
+ rspec-core (3.12.0)
26
+ rspec-support (~> 3.12.0)
27
+ rspec-expectations (3.12.0)
43
28
  diff-lcs (>= 1.2.0, < 2.0)
44
- rspec-support (~> 3.11.0)
45
- rspec-mocks (3.11.1)
29
+ rspec-support (~> 3.12.0)
30
+ rspec-mocks (3.12.0)
46
31
  diff-lcs (>= 1.2.0, < 2.0)
47
- rspec-support (~> 3.11.0)
48
- rspec-support (3.11.0)
49
- syntax_tree (3.5.0)
50
- prettier_print
51
- syntax_tree-haml (1.3.1)
52
- haml (>= 5.2)
53
- prettier_print
54
- syntax_tree (>= 2.0.1)
55
- syntax_tree-rbs (0.5.0)
56
- prettier_print
57
- rbs
58
- syntax_tree (>= 2.0.1)
59
- temple (0.8.2)
60
- tilt (2.0.11)
61
- tzinfo (2.0.5)
62
- concurrent-ruby (~> 1.0)
63
- zeitwerk (2.6.0)
32
+ rspec-support (~> 3.12.0)
33
+ rspec-support (3.12.0)
34
+ ruby-prof (1.4.3)
35
+ zeitwerk (2.6.6)
64
36
 
65
37
  PLATFORMS
66
38
  arm64-darwin-21
67
39
 
68
40
  DEPENDENCIES
69
41
  code-ruby!
70
- prettier (~> 3)
71
- rspec (~> 3)
42
+ rspec
43
+ ruby-prof
44
+ syntax_tree!
72
45
  template-ruby!
73
46
 
74
47
  BUNDLED WITH
data/TODO ADDED
@@ -0,0 +1,17 @@
1
+ - Class
2
+ - Function parameters regular splat *args
3
+ - Function parameters keyword splat **kargs
4
+ - Function parameters block &block
5
+ - Block parameters regular splat *args
6
+ - Block parameters keyword splat **kargs
7
+ - Block parameters block &block
8
+ - Dictionnary regular splat { *args }
9
+ - Dictionnary keyword splat { **kargs }
10
+ - Dictionnary block { &block }
11
+ - Dictionnary expand name { user } and { user: }
12
+ - Rescue with exception name, rescue Code::Undefined
13
+ - Rescue with exception catched, rescue => e
14
+ - begin end
15
+ - begin rescue end
16
+ - begin rescue ensure end
17
+ - begin rescue else end
data/bin/code CHANGED
@@ -3,49 +3,74 @@
3
3
  require "optparse"
4
4
  require_relative "../lib/template-ruby"
5
5
 
6
- options = { timeout: 0 }
7
-
8
- OptionParser.new do |opts|
9
- opts.banner = "Usage: bin/code [options]"
10
-
11
- opts.on(
12
- "-i INPUT",
13
- "--input=INPUT",
14
- "Input in the code language (String or File)"
15
- ) do |input|
16
- if File.exists?(input)
17
- input = File.read(input)
6
+ options = { timeout: 0, profile: false }
7
+
8
+ OptionParser
9
+ .new do |opts|
10
+ opts.banner = "Usage: bin/code [options]"
11
+
12
+ opts.on(
13
+ "-i INPUT",
14
+ "--input=INPUT",
15
+ "Input in the code language (String or File)"
16
+ ) do |input|
17
+ input = File.read(input) if File.exists?(input)
18
+
19
+ options[:input] = input
18
20
  end
19
21
 
20
- options[:input] = input
21
- end
22
+ opts.on(
23
+ "-c CONTEXT",
24
+ "--context=CONTEXT",
25
+ "Context in the code language (String or File)"
26
+ ) do |context|
27
+ context = File.read(context) if File.exists?(context)
22
28
 
23
- opts.on(
24
- "-c CONTEXT",
25
- "--context=CONTEXT",
26
- "Context in the code language (String or File)"
27
- ) do |context|
28
- if File.exists?(context)
29
- context = File.read(context)
29
+ options[:context] = context
30
30
  end
31
31
 
32
- options[:context] = context
33
- end
32
+ opts.on("-p", "--parse", "Get parser results for input") do |parse|
33
+ options[:parse] = parse
34
+ end
34
35
 
35
- opts.on("-p", "--parse", "Get parser results for input") do |parse|
36
- options[:parse] = parse
37
- end
36
+ opts.on(
37
+ "-t TIMEOUT",
38
+ "--timeout=TIMEOUT",
39
+ "Set timeout in seconds"
40
+ ) { |timeout| options[:timeout] = timeout.to_f }
38
41
 
39
- opts.on("-t TIMEOUT", "--timeout=TIMEOUT", "Set timeout in seconds") do |timeout|
40
- options[:timeout] = timeout.to_f
42
+ opts.on(
43
+ "--profile",
44
+ "Profile Ruby code"
45
+ ) do |timeout|
46
+ require "ruby-prof"
47
+ options[:profile] = true
48
+ end
41
49
  end
42
- end.parse!
50
+ .parse!
43
51
 
44
52
  input = options.fetch(:input, "")
45
53
  context = options.fetch(:context, "")
46
54
 
55
+ if options[:profile]
56
+ RubyProf.start
57
+ end
58
+
47
59
  if options[:parse]
48
- pp ::Code::Parser::Code.new.parse(input)
60
+ pp ::Code::Parser.parse(input).to_raw
49
61
  else
50
- print Code.evaluate(input, context, io: $stdout, timeout: options[:timeout]).to_s
62
+ print(
63
+ Code.evaluate(
64
+ input,
65
+ context,
66
+ io: $stdout,
67
+ timeout: options[:timeout]
68
+ ).to_s
69
+ )
70
+ end
71
+
72
+ if options[:profile]
73
+ result = RubyProf.stop
74
+ printer = RubyProf::FlatPrinter.new(result)
75
+ printer.print($stdout)
51
76
  end
data/bin/format ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env fish
2
+
3
+ stree write Gemfile lib/**/*.rb spec/**/*.rb bin/code-parser
data/bin/template CHANGED
@@ -3,41 +3,83 @@
3
3
  require "optparse"
4
4
  require_relative "../lib/template-ruby"
5
5
 
6
- options = { timeout: 0 }
6
+ options = { timeout: 0, profile: false, profiler: "text" }
7
7
 
8
- OptionParser.new do |opts|
9
- opts.banner = "Usage: template [options]"
8
+ OptionParser
9
+ .new do |opts|
10
+ opts.banner = "Usage: template [options]"
10
11
 
11
- opts.on("-i INPUT", "--input=INPUT", "Input in the template language (String or File)") do |input|
12
- if File.exists?(input)
13
- input = File.read(input)
12
+ opts.on(
13
+ "-i INPUT",
14
+ "--input=INPUT",
15
+ "Input in the template language (String or File)"
16
+ ) do |input|
17
+ input = File.read(input) if File.exists?(input)
18
+
19
+ options[:input] = input
14
20
  end
15
21
 
16
- options[:input] = input
17
- end
22
+ opts.on(
23
+ "-c CONTEXT",
24
+ "--context=CONTEXT",
25
+ "Context in the code language (String or File)"
26
+ ) do |context|
27
+ context = File.read(context) if File.exists?(context)
18
28
 
19
- opts.on("-c CONTEXT", "--context=CONTEXT", "Context in the code language (String or File)") do |context|
20
- if File.exists?(context)
21
- context = File.read(context)
29
+ options[:context] = context
22
30
  end
23
31
 
24
- options[:context] = context
25
- end
32
+ opts.on("-p", "--parse", "Get parser results for input") do |parse|
33
+ options[:parse] = parse
34
+ end
26
35
 
27
- opts.on("-p", "--parse", "Get parser results for input") do |parse|
28
- options[:parse] = parse
29
- end
36
+ opts.on(
37
+ "-t TIMEOUT",
38
+ "--timeout=TIMEOUT",
39
+ "Set timeout in seconds"
40
+ ) { |timeout| options[:timeout] = timeout.to_f }
41
+
42
+ opts.on(
43
+ "--profile",
44
+ "Profile Ruby code"
45
+ ) do |timeout|
46
+ require "ruby-prof"
47
+ options[:profile] = true
48
+ end
30
49
 
31
- opts.on("-t TIMEOUT", "--timeout=TIMEOUT", "Set timeout in seconds") do |timeout|
32
- options[:timeout] = timeout.to_f
50
+ opts.on(
51
+ "--profiler TYPE",
52
+ "Profiler output type (text (default) or html)"
53
+ ) do |profiler|
54
+ require "ruby-prof"
55
+ options[:profile] = true
56
+ options[:profiler] = profiler
57
+ end
33
58
  end
34
- end.parse!
59
+ .parse!
35
60
 
36
61
  input = options.fetch(:input, "")
37
62
  context = options.fetch(:context, "")
38
63
 
64
+ if options[:profile]
65
+ RubyProf.start
66
+ end
67
+
39
68
  if options[:parse]
40
- pp ::Template::Parser::Template.new.parse(input)
69
+ pp ::Template::Parser.parse(input).to_raw
41
70
  else
42
71
  Template.render(input, context, io: $stdout, timeout: options[:timeout])
43
72
  end
73
+
74
+ if options[:profile]
75
+ result = RubyProf.stop
76
+ if options[:profiler] == "text"
77
+ printer = RubyProf::FlatPrinter.new(result)
78
+ printer.print($stdout)
79
+ elsif options[:profiler] == "html"
80
+ printer = RubyProf::GraphHtmlPrinter.new(result)
81
+ printer.print($stdout)
82
+ else
83
+ abort "#{options[:profiler]} not recognized"
84
+ end
85
+ end
data/bin/test ADDED
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ rspec
6
+
7
+ for f in docs/**/*.template
8
+ do
9
+ echo $f
10
+ bin/template -i $f -p > /dev/null
11
+ done
12
+
13
+ for f in docs/*.code
14
+ do
15
+ echo $f
16
+ bin/code -i $f -p > /dev/null
17
+ done
data/code-ruby.gemspec CHANGED
@@ -13,10 +13,5 @@ Gem::Specification.new do |s|
13
13
  s.homepage = "https://github.com/dorianmariefr/template-ruby"
14
14
  s.license = "MIT"
15
15
 
16
- s.add_dependency "activesupport", "~> 7"
17
- s.add_dependency "parslet", "~> 2"
18
- s.add_dependency "zeitwerk", "~> 2.6"
19
-
20
- s.add_development_dependency "prettier", "~> 3"
21
- s.add_development_dependency "rspec", "~> 3"
16
+ s.add_dependency "zeitwerk", "~> 2"
22
17
  end
data/docs/class.code ADDED
@@ -0,0 +1,9 @@
1
+ class ApiClient
2
+ get = (url) => {
3
+ fetch(url)
4
+ }
5
+ end
6
+
7
+ class Twitter < ApiClient
8
+ self.base_url = "https://api.twitter.com"
9
+ end
@@ -1,14 +1,10 @@
1
1
  {
2
2
  sum = 0
3
3
 
4
- i = 1
5
-
6
- while i < 1000
4
+ 1000.times do |i|
7
5
  if i % 3 == 0 or i % 5 == 0
8
6
  sum += i
9
7
  end
10
-
11
- i += 1
12
8
  end
13
9
 
14
10
  sum
@@ -11,4 +11,3 @@
11
11
  i % j == 0
12
12
  end
13
13
  end
14
- }
data/docs/meetup.code ADDED
@@ -0,0 +1,12 @@
1
+ url = fetch(:url) { "https://www.meetup.com/parisrb" }
2
+ response = HTTP.get(url)
3
+ times = response.css(".groupHome-eventsList-upcomingEvents time")
4
+ times = times.map(&:datetime).map { |time| Time.from_epoch(time.to_integer) }
5
+
6
+ times.each do |time|
7
+ if (1.day.from_now...(1.day.from_now + 1.hour)).include?(time)
8
+ Sms.send("Event in one day {url}")
9
+ elsif (2.hours.from_now...(1.hour.from_now)).include(time)
10
+ Sms.send("Event in two hours {url}")
11
+ end
12
+ end
@@ -1,69 +1,36 @@
1
1
  - Code
2
- - {a = "Go" a += "od" a}
3
2
  - Statement
4
- - {a = "Good"}
5
3
  - Equality
6
- - {1 == 1 ? "Good"}
4
+ - Splat
5
+ - Class
7
6
  - While
8
- - {a = 0
9
- while a < 10 a += 1 "Good" end}
10
7
  - If
11
- - {if true "Good" end}
12
8
  - IfModifier
13
- - {"Good" if true}
14
9
  - OrKeyword
15
- - {false or "Good"}
16
10
  - NotKeyword
17
- - {not false and "Good"}
18
11
  - Equal
19
- - {a = "Good"}
20
12
  - Rescue
21
- - {0 > "String" rescue "Good"}
22
13
  - Ternary
23
- - {nothing ? "Bad" : "Good"}
24
- - Defined
25
- - {a = 1 "Good" if defined?(a)}
26
14
  - Range
27
- - {("Good".."Bad").first}
28
15
  - OrOperator
29
- - {false || "Good"}
30
16
  - AndOperator
31
- - {"Bad" && "Good"}
32
- - GreaterThan
33
- - {2 > 1 ? "Good"}
17
+ - EqualityLower
18
+ - Greater
34
19
  - BitwiseOr
35
- - {2 | 1 == 3 ? "Good"}
36
20
  - BitwiseAnd
37
- - {2 & 1 == 0 ? "Good"}
38
21
  - Shift
39
- - {1 << 1 == 2 ? "Good"}
40
22
  - Addition
41
- - {1 + 1 == 2 ? "Good"}
42
23
  - Multiplication
43
- - {1 * 2 == 2 ? "Good"}
44
24
  - UnaryMinus
45
- - {-1 == 1 - 2 ? "Good"}
46
25
  - Power
47
- - {2 ** 2 == 4 ? "Good"}
48
26
  - Negation
49
- - {!false ? "Good"}
50
27
  - Function
51
- - {good = () => { "Good" } good}
52
- - Call
53
- - {["Good"].first}
28
+ - ChainedCall
54
29
  - Dictionnary
55
- - {{a: "Good"}.a}
56
30
  - List
57
- - {["Good", "Bad"].first}
58
31
  - String
59
- - {"Good"}
60
32
  - Number
61
- - {1 == 1 ? "Good"}
62
33
  - Boolean
63
- - {true ? "Good"}
64
34
  - Nothing
65
- - {nothing ? "Bad" : "Good"}
66
35
  - Group
67
- - {(a = 0 a += 1 a) == 1 ? "Good"}
68
- - Name
69
- - {a = "Good" a}
36
+ - Call
data/docs/rain.code ADDED
@@ -0,0 +1,22 @@
1
+ paris = { latitude: 48.8566, longitude: 2.4022 }
2
+ latitude = fetch(:latitude) { paris.latitude }
3
+ longitude = fetch(:longitude) { paris.longitude }
4
+ duration = fetch(:duration) { 1.hour }
5
+ hour = duration.from_now.hour
6
+
7
+ response =
8
+ HTTP.get(
9
+ "https://api.open-meteo.com/v1/forecast",
10
+ parameters: {
11
+ latitude: latitude,
12
+ longitude: longitude,
13
+ hourly: :precipitation
14
+ }
15
+ )
16
+
17
+ precipitation = response.hourly.precipitation[hour]
18
+ precipitation = (precipitation * 100).to_integer
19
+
20
+ if precipitation > 0
21
+ Sms.send("There will be {precipitation}% of precipitation in the next hour")
22
+ end
data/docs/slack.code ADDED
@@ -0,0 +1,17 @@
1
+ Slack.send("Who is leading the syncs?", channel: "#team-template")
2
+
3
+ Twitter.send("What do you want to do this week?")
4
+
5
+ Discord.send("Who will be the game master this week?")
6
+
7
+ Email.send(
8
+ subject: "What did you do last week?",
9
+ from: "dorian@thoughtbot.com",
10
+ reply_to: "rob@thoughtbot.com"
11
+ )
12
+
13
+ Email.send(
14
+ subject: "What do you want to do this week?",
15
+ from: "dorian@thoughtbot.com",
16
+ reply_to: "rob@thoughtbot.com"
17
+ )
data/docs/stripe.code ADDED
@@ -0,0 +1,7 @@
1
+ event = Stripe::Webhook.event
2
+
3
+ if event.type == "payment_intent.succeeded"
4
+ payment_intent = event.data.object
5
+ amount = Money.format(payment_intent.amount, payment_intent.currency)
6
+ Sms.send("You got paid {amount}")
7
+ end
data/docs/twitter.code ADDED
@@ -0,0 +1,9 @@
1
+ twitter_username = fetch(:twitter_username) { "dorianmariefr" }
2
+
3
+ Twitter
4
+ .search("to:{twitter_username}", type: :recent)
5
+ .each do |tweet|
6
+ next if Storage.exists?(tweet.id)
7
+ Storage.create!(tweet.id)
8
+ Sms.send("New mention: {tweet.user.screen_name}: {tweet.text}")
9
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "lib/template/version"
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "language-ruby"
5
+ s.version = ::Template::Version
6
+ s.summary = "A Parsing Expression Grammar (PEG)"
7
+ s.description =
8
+ 'A Parsing Expression Grammar (PEG) for making parsers'
9
+ s.authors = ["Dorian Marié"]
10
+ s.email = "dorian@dorianmarie.fr"
11
+ s.files = `git ls-files`.split($/)
12
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
13
+ s.require_paths = ["lib"]
14
+ s.homepage = "https://github.com/dorianmariefr/template-ruby"
15
+ s.license = "MIT"
16
+
17
+ s.add_dependency "zeitwerk", "~> 2"
18
+ end
data/lib/code/error.rb CHANGED
@@ -11,5 +11,8 @@ class Code
11
11
 
12
12
  class ArgumentError < ::Code::Error
13
13
  end
14
+
15
+ class IncompatibleContext < ::Code::Error
16
+ end
14
17
  end
15
18
  end
@@ -0,0 +1,29 @@
1
+ class Code
2
+ class Node
3
+ class Base10 < Node
4
+ def initialize(parsed)
5
+ @whole = parsed.delete(:whole)
6
+
7
+ if parsed.key?(:exponent)
8
+ @exponent = Node::Statement.new(parsed.delete(:exponent))
9
+ end
10
+
11
+ super(parsed)
12
+ end
13
+
14
+ def evaluate(**args)
15
+ if @exponent
16
+ exponent = @exponent.evaluate(**args)
17
+
18
+ if exponent.is_a?(::Code::Object::Integer)
19
+ ::Code::Object::Integer.new(@whole.to_i, exponent: exponent)
20
+ else
21
+ ::Code::Object::Decimal.new(@whole, exponent: exponent)
22
+ end
23
+ else
24
+ ::Code::Object::Integer.new(@whole.to_i)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Node
3
+ class Base16 < Node
4
+ def initialize(parsed)
5
+ @base_16 = parsed
6
+ end
7
+
8
+ def evaluate(**args)
9
+ ::Code::Object::Integer.new(@base_16.to_i(16))
10
+ end
11
+ end
12
+ end
13
+ end