prompter-ruby 0.1.1 → 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.
- checksums.yaml +4 -4
- data/README.md +29 -15
- data/lib/prompter_ruby/filters.rb +52 -0
- data/lib/prompter_ruby/nodes/comment_node.rb +15 -0
- data/lib/prompter_ruby/nodes/if_node.rb +60 -5
- data/lib/prompter_ruby/nodes/raw_node.rb +15 -0
- data/lib/prompter_ruby/nodes/set_node.rb +53 -0
- data/lib/prompter_ruby/nodes/variable_node.rb +9 -4
- data/lib/prompter_ruby/parser.rb +55 -1
- data/lib/prompter_ruby/version.rb +1 -1
- data/lib/prompter_ruby.rb +4 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c21c7bea53b34f25eed8b9b186c5212d23033bd2600110125c85210b91052e85
|
|
4
|
+
data.tar.gz: f0f14bfcf7d30ad14d02d93e475d1a1d002aa548df5328002579fba950043089
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ac3b64c564a9aafe1859ad333147318f46d6d9e0194760bcd78528fe0e737fe78bc45c3b2a917d54131f24d256bc6a9d619631d0a2c58304de6d6871577cb72
|
|
7
|
+
data.tar.gz: c0e98a881337ab38b3806ffe199a9be57d7632d6bb1a0f1dc85dbbcc3685f8d74ba5e5ce1b51e09fdd2c2d960e476f51218f1182852b2f29114320c636704d6c
|
data/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# prompter-ruby
|
|
2
2
|
|
|
3
|
-
Prompt template engine for Ruby with variables, conditionals,
|
|
3
|
+
Prompt template engine for Ruby. Render dynamic prompts with variables, conditionals, and loops.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
gem "prompter-ruby"
|
|
8
|
+
gem "prompter-ruby"
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
@@ -13,25 +13,39 @@ gem "prompter-ruby", "~> 0.1"
|
|
|
13
13
|
```ruby
|
|
14
14
|
require "prompter_ruby"
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# Basic variable interpolation
|
|
17
|
+
template = PrompterRuby::Template.new("Hello, {{name}}!")
|
|
18
|
+
template.render(name: "World") # => "Hello, World!"
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{%
|
|
20
|
+
# Conditionals and loops
|
|
21
|
+
source = <<~TMPL
|
|
22
|
+
You are a {{role}} assistant.
|
|
23
|
+
{% if context %}Use this context: {{context}}{% endif %}
|
|
24
|
+
{% for item in items %}
|
|
25
|
+
- {{item}}
|
|
22
26
|
{% endfor %}
|
|
23
|
-
|
|
27
|
+
TMPL
|
|
28
|
+
template = PrompterRuby::Template.new(source)
|
|
29
|
+
template.render(role: "helpful", items: ["A", "B", "C"])
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
context: "Some info",
|
|
28
|
-
rules: ["Be concise", "Be helpful"]
|
|
29
|
-
)
|
|
31
|
+
# Strict mode (raise on undefined variables)
|
|
32
|
+
template.render({ name: "World" }, strict: true)
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
template
|
|
34
|
+
# Validation
|
|
35
|
+
template.valid? # => true/false
|
|
36
|
+
template.validate! # raises ParseError if invalid
|
|
33
37
|
```
|
|
34
38
|
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- `{{variable}}` interpolation with nested key access
|
|
42
|
+
- `{% if %}` / `{% else %}` / `{% endif %}` conditionals
|
|
43
|
+
- `{% for x in items %}` / `{% endfor %}` loops
|
|
44
|
+
- Strict mode raises `UndefinedVariableError` for missing variables
|
|
45
|
+
- ParseError with line numbers for unclosed blocks
|
|
46
|
+
- Template validation (`valid?`, `validate!`)
|
|
47
|
+
- Whitespace trimming for tag-only lines
|
|
48
|
+
|
|
35
49
|
## License
|
|
36
50
|
|
|
37
51
|
MIT
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module PrompterRuby
|
|
6
|
+
module Filters
|
|
7
|
+
REGISTRY = {
|
|
8
|
+
"upcase" => ->(v, _) { v.to_s.upcase },
|
|
9
|
+
"downcase" => ->(v, _) { v.to_s.downcase },
|
|
10
|
+
"capitalize" => ->(v, _) { v.to_s.capitalize },
|
|
11
|
+
"strip" => ->(v, _) { v.to_s.strip },
|
|
12
|
+
"reverse" => ->(v, _) { v.respond_to?(:reverse) ? v.reverse : v.to_s.reverse },
|
|
13
|
+
"size" => ->(v, _) { v.respond_to?(:size) ? v.size : v.to_s.size },
|
|
14
|
+
"first" => ->(v, _) { v.respond_to?(:first) ? v.first : v },
|
|
15
|
+
"last" => ->(v, _) { v.respond_to?(:last) ? v.last : v },
|
|
16
|
+
"json" => ->(v, _) { JSON.generate(v) },
|
|
17
|
+
"escape" => ->(v, _) { escape_html(v.to_s) },
|
|
18
|
+
"truncate" => ->(v, arg) { n = (arg || 100).to_i; v.to_s.length > n ? v.to_s[0...n] + "..." : v.to_s },
|
|
19
|
+
"join" => ->(v, arg) { v.respond_to?(:join) ? v.join(arg || ", ") : v.to_s },
|
|
20
|
+
"default" => ->(v, arg) { (v.nil? || (v.respond_to?(:empty?) && v.empty?)) ? arg : v },
|
|
21
|
+
"replace" => ->(v, arg) { parts = arg.to_s.split(",", 2).map(&:strip); v.to_s.gsub(parts[0].to_s, parts[1].to_s) }
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
def self.apply(value, filter_chain)
|
|
25
|
+
filter_chain.each do |name, arg|
|
|
26
|
+
filter = REGISTRY[name]
|
|
27
|
+
raise RenderError, "Unknown filter: '#{name}'" unless filter
|
|
28
|
+
value = filter.call(value, arg)
|
|
29
|
+
end
|
|
30
|
+
value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.parse(expression)
|
|
34
|
+
parts = expression.split("|")
|
|
35
|
+
var_name = parts.shift.strip
|
|
36
|
+
filters = parts.map do |f|
|
|
37
|
+
f = f.strip
|
|
38
|
+
if f.include?(":")
|
|
39
|
+
name, arg = f.split(":", 2)
|
|
40
|
+
[name.strip, arg.strip.delete("'\"")]
|
|
41
|
+
else
|
|
42
|
+
[f, nil]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
[var_name, filters]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.escape_html(str)
|
|
49
|
+
str.gsub("&", "&").gsub("<", "<").gsub(">", ">").gsub('"', """).gsub("'", "'")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -3,36 +3,91 @@
|
|
|
3
3
|
module PrompterRuby
|
|
4
4
|
module Nodes
|
|
5
5
|
class IfNode
|
|
6
|
-
|
|
6
|
+
COMPARISON_OPS = %w[== != >= <= > <].freeze
|
|
7
|
+
|
|
8
|
+
def initialize(condition, true_nodes, false_nodes = [], elsif_branches: [])
|
|
7
9
|
@condition = condition.strip
|
|
8
10
|
@true_nodes = true_nodes
|
|
9
11
|
@false_nodes = false_nodes
|
|
12
|
+
@elsif_branches = elsif_branches # Array of [condition, nodes]
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
def render(context)
|
|
13
|
-
if evaluate_condition(context)
|
|
16
|
+
if evaluate_condition(@condition, context)
|
|
14
17
|
@true_nodes.map { |n| n.render(context) }.join
|
|
15
18
|
else
|
|
19
|
+
@elsif_branches.each do |cond, nodes|
|
|
20
|
+
if evaluate_condition(cond, context)
|
|
21
|
+
return nodes.map { |n| n.render(context) }.join
|
|
22
|
+
end
|
|
23
|
+
end
|
|
16
24
|
@false_nodes.map { |n| n.render(context) }.join
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
private
|
|
21
29
|
|
|
22
|
-
def evaluate_condition(context)
|
|
23
|
-
|
|
24
|
-
condition
|
|
30
|
+
def evaluate_condition(condition, context)
|
|
31
|
+
# Boolean operators (and/or)
|
|
32
|
+
if condition.include?(" and ")
|
|
33
|
+
parts = condition.split(" and ", 2)
|
|
34
|
+
return evaluate_condition(parts[0].strip, context) && evaluate_condition(parts[1].strip, context)
|
|
35
|
+
end
|
|
36
|
+
if condition.include?(" or ")
|
|
37
|
+
parts = condition.split(" or ", 2)
|
|
38
|
+
return evaluate_condition(parts[0].strip, context) || evaluate_condition(parts[1].strip, context)
|
|
39
|
+
end
|
|
25
40
|
|
|
41
|
+
negate = false
|
|
26
42
|
if condition.start_with?("not ")
|
|
27
43
|
negate = true
|
|
28
44
|
condition = condition.sub("not ", "").strip
|
|
29
45
|
end
|
|
30
46
|
|
|
47
|
+
# Comparison operators
|
|
48
|
+
COMPARISON_OPS.each do |op|
|
|
49
|
+
if condition.include?(" #{op} ")
|
|
50
|
+
left, right = condition.split(" #{op} ", 2).map(&:strip)
|
|
51
|
+
left_val = resolve_or_literal(left, context)
|
|
52
|
+
right_val = resolve_or_literal(right, context)
|
|
53
|
+
result = compare(left_val, right_val, op)
|
|
54
|
+
return negate ? !result : result
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
31
58
|
value = resolve_value(condition, context)
|
|
32
59
|
result = truthy?(value)
|
|
33
60
|
negate ? !result : result
|
|
34
61
|
end
|
|
35
62
|
|
|
63
|
+
def compare(a, b, op)
|
|
64
|
+
case op
|
|
65
|
+
when "==" then a == b
|
|
66
|
+
when "!=" then a != b
|
|
67
|
+
when ">" then a.to_f > b.to_f
|
|
68
|
+
when ">=" then a.to_f >= b.to_f
|
|
69
|
+
when "<" then a.to_f < b.to_f
|
|
70
|
+
when "<=" then a.to_f <= b.to_f
|
|
71
|
+
else false
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def resolve_or_literal(expr, context)
|
|
76
|
+
# String literal
|
|
77
|
+
if expr.match?(/\A['"](.*)['"]/)
|
|
78
|
+
return expr[1..-2]
|
|
79
|
+
end
|
|
80
|
+
# Numeric literal
|
|
81
|
+
if expr.match?(/\A-?\d+(\.\d+)?\z/)
|
|
82
|
+
return expr.include?(".") ? expr.to_f : expr.to_i
|
|
83
|
+
end
|
|
84
|
+
# Boolean
|
|
85
|
+
return true if expr == "true"
|
|
86
|
+
return false if expr == "false"
|
|
87
|
+
# Variable
|
|
88
|
+
resolve_value(expr, context)
|
|
89
|
+
end
|
|
90
|
+
|
|
36
91
|
def resolve_value(name, context)
|
|
37
92
|
parts = name.split(".")
|
|
38
93
|
value = context
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PrompterRuby
|
|
4
|
+
module Nodes
|
|
5
|
+
class SetNode
|
|
6
|
+
def initialize(name, value_expr)
|
|
7
|
+
@name = name.strip
|
|
8
|
+
@value_expr = value_expr.strip
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def render(context)
|
|
12
|
+
value = evaluate(@value_expr, context)
|
|
13
|
+
context[@name.to_sym] = value
|
|
14
|
+
""
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def evaluate(expr, context)
|
|
20
|
+
# String literal
|
|
21
|
+
if expr.match?(/\A["'](.*)["']\z/)
|
|
22
|
+
return expr[1..-2]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Numeric
|
|
26
|
+
if expr.match?(/\A-?\d+(\.\d+)?\z/)
|
|
27
|
+
return expr.include?(".") ? expr.to_f : expr.to_i
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Boolean
|
|
31
|
+
return true if expr == "true"
|
|
32
|
+
return false if expr == "false"
|
|
33
|
+
|
|
34
|
+
# Variable reference
|
|
35
|
+
resolve(expr, context)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def resolve(name, context)
|
|
39
|
+
parts = name.split(".")
|
|
40
|
+
value = context
|
|
41
|
+
parts.each do |part|
|
|
42
|
+
if value.is_a?(Hash)
|
|
43
|
+
key = value.key?(part.to_sym) ? part.to_sym : part
|
|
44
|
+
value = value[key]
|
|
45
|
+
else
|
|
46
|
+
return nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -6,23 +6,28 @@ module PrompterRuby
|
|
|
6
6
|
attr_reader :name
|
|
7
7
|
|
|
8
8
|
def initialize(name)
|
|
9
|
-
@
|
|
9
|
+
@raw = name.strip
|
|
10
|
+
@var_name, @filters = Filters.parse(@raw)
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def render(context)
|
|
13
14
|
value = resolve(context)
|
|
14
15
|
|
|
15
16
|
if value.nil? && context[:__strict__]
|
|
16
|
-
raise UndefinedVariableError, "Undefined variable: '#{@
|
|
17
|
+
raise UndefinedVariableError, "Undefined variable: '#{@var_name}'"
|
|
17
18
|
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
if @filters.any?
|
|
21
|
+
Filters.apply(value, @filters).to_s
|
|
22
|
+
else
|
|
23
|
+
value.to_s
|
|
24
|
+
end
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
private
|
|
23
28
|
|
|
24
29
|
def resolve(context)
|
|
25
|
-
parts = @
|
|
30
|
+
parts = @var_name.split(".")
|
|
26
31
|
value = context
|
|
27
32
|
|
|
28
33
|
parts.each do |part|
|
data/lib/prompter_ruby/parser.rb
CHANGED
|
@@ -4,6 +4,7 @@ module PrompterRuby
|
|
|
4
4
|
class Parser
|
|
5
5
|
VARIABLE_PATTERN = /\{\{(.*?)\}\}/
|
|
6
6
|
TAG_PATTERN = /\{%(.*?)%\}/
|
|
7
|
+
COMMENT_PATTERN = /\{#(.*?)#\}/m
|
|
7
8
|
|
|
8
9
|
def parse(source)
|
|
9
10
|
tokens = tokenize(source)
|
|
@@ -21,6 +22,7 @@ module PrompterRuby
|
|
|
21
22
|
while scanner.length > 0
|
|
22
23
|
var_match = scanner.match(VARIABLE_PATTERN)
|
|
23
24
|
tag_match = scanner.match(TAG_PATTERN)
|
|
25
|
+
comment_match = scanner.match(COMMENT_PATTERN)
|
|
24
26
|
|
|
25
27
|
next_match = nil
|
|
26
28
|
next_pos = scanner.length
|
|
@@ -35,6 +37,11 @@ module PrompterRuby
|
|
|
35
37
|
next_pos = tag_match.begin(0)
|
|
36
38
|
end
|
|
37
39
|
|
|
40
|
+
if comment_match && comment_match.begin(0) < next_pos
|
|
41
|
+
next_match = :comment
|
|
42
|
+
next_pos = comment_match.begin(0)
|
|
43
|
+
end
|
|
44
|
+
|
|
38
45
|
if next_pos > 0
|
|
39
46
|
tokens << [:text, scanner[0...next_pos], line_number(source, offset)]
|
|
40
47
|
end
|
|
@@ -48,6 +55,10 @@ module PrompterRuby
|
|
|
48
55
|
tokens << [:tag, tag_match[1].strip, line_number(source, offset + tag_match.begin(0))]
|
|
49
56
|
offset += tag_match.end(0)
|
|
50
57
|
scanner = scanner[tag_match.end(0)..]
|
|
58
|
+
when :comment
|
|
59
|
+
tokens << [:comment, comment_match[1].strip, line_number(source, offset + comment_match.begin(0))]
|
|
60
|
+
offset += comment_match.end(0)
|
|
61
|
+
scanner = scanner[comment_match.end(0)..]
|
|
51
62
|
else
|
|
52
63
|
break
|
|
53
64
|
end
|
|
@@ -144,6 +155,9 @@ module PrompterRuby
|
|
|
144
155
|
when :text
|
|
145
156
|
nodes << Nodes::TextNode.new(value)
|
|
146
157
|
index += 1
|
|
158
|
+
when :comment
|
|
159
|
+
nodes << Nodes::CommentNode.new(value)
|
|
160
|
+
index += 1
|
|
147
161
|
when :variable
|
|
148
162
|
nodes << Nodes::VariableNode.new(value)
|
|
149
163
|
index += 1
|
|
@@ -164,7 +178,23 @@ module PrompterRuby
|
|
|
164
178
|
|
|
165
179
|
index = index + 1 + end_index
|
|
166
180
|
|
|
181
|
+
# Handle elsif/else chains
|
|
182
|
+
elsif_branches = []
|
|
167
183
|
false_nodes = []
|
|
184
|
+
|
|
185
|
+
while tokens[index] && tokens[index][1]&.start_with?("elsif ")
|
|
186
|
+
elsif_cond = tokens[index][1].sub("elsif ", "").strip
|
|
187
|
+
elsif_line = tokens[index][2]
|
|
188
|
+
result = parse_nodes(tokens[(index + 1)..], stop_tags: ["elsif", "else", "endif"], open_tag: "elsif", open_line: elsif_line)
|
|
189
|
+
if result.is_a?(Array) && result.length == 2
|
|
190
|
+
elsif_nodes, end_index = result
|
|
191
|
+
else
|
|
192
|
+
raise ParseError, "Unclosed 'elsif' block starting at line #{elsif_line}"
|
|
193
|
+
end
|
|
194
|
+
elsif_branches << [elsif_cond, elsif_nodes]
|
|
195
|
+
index = index + 1 + end_index
|
|
196
|
+
end
|
|
197
|
+
|
|
168
198
|
if tokens[index] && tokens[index][1]&.start_with?("else")
|
|
169
199
|
else_line = tokens[index][2]
|
|
170
200
|
result = parse_nodes(tokens[(index + 1)..], stop_tags: ["endif"], open_tag: "else", open_line: else_line)
|
|
@@ -185,7 +215,7 @@ module PrompterRuby
|
|
|
185
215
|
|
|
186
216
|
index += 1
|
|
187
217
|
|
|
188
|
-
nodes << Nodes::IfNode.new(condition, true_nodes, false_nodes)
|
|
218
|
+
nodes << Nodes::IfNode.new(condition, true_nodes, false_nodes, elsif_branches: elsif_branches)
|
|
189
219
|
elsif value.start_with?("for ")
|
|
190
220
|
match = value.match(/for\s+(\w+)\s+in\s+(\S+)/)
|
|
191
221
|
raise ParseError, "Invalid for syntax: #{value}" unless match
|
|
@@ -209,6 +239,30 @@ module PrompterRuby
|
|
|
209
239
|
index = index + 1 + end_index + 1
|
|
210
240
|
|
|
211
241
|
nodes << Nodes::ForNode.new(item_name, collection_name, body_nodes)
|
|
242
|
+
elsif value == "raw"
|
|
243
|
+
# Collect raw tokens until endraw, reconstructing original syntax
|
|
244
|
+
raw_text = ""
|
|
245
|
+
index += 1
|
|
246
|
+
while index < tokens.length
|
|
247
|
+
type_r, value_r, = tokens[index]
|
|
248
|
+
if type_r == :tag && value_r == "endraw"
|
|
249
|
+
index += 1
|
|
250
|
+
break
|
|
251
|
+
end
|
|
252
|
+
case type_r
|
|
253
|
+
when :text, :text_skip then raw_text += value_r
|
|
254
|
+
when :variable then raw_text += "{{#{value_r}}}"
|
|
255
|
+
when :tag then raw_text += "{%#{value_r}%}"
|
|
256
|
+
when :comment then raw_text += "{##{value_r}#}"
|
|
257
|
+
end
|
|
258
|
+
index += 1
|
|
259
|
+
end
|
|
260
|
+
nodes << Nodes::RawNode.new(raw_text)
|
|
261
|
+
elsif value.start_with?("set ")
|
|
262
|
+
match = value.match(/set\s+(\w+)\s*=\s*(.+)/)
|
|
263
|
+
raise ParseError, "Invalid set syntax: #{value}" unless match
|
|
264
|
+
nodes << Nodes::SetNode.new(match[1], match[2])
|
|
265
|
+
index += 1
|
|
212
266
|
else
|
|
213
267
|
nodes << Nodes::TextNode.new("{%#{value}%}")
|
|
214
268
|
index += 1
|
data/lib/prompter_ruby.rb
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "prompter_ruby/version"
|
|
4
4
|
require_relative "prompter_ruby/errors"
|
|
5
|
+
require_relative "prompter_ruby/filters"
|
|
5
6
|
require_relative "prompter_ruby/nodes/text_node"
|
|
6
7
|
require_relative "prompter_ruby/nodes/variable_node"
|
|
7
8
|
require_relative "prompter_ruby/nodes/if_node"
|
|
8
9
|
require_relative "prompter_ruby/nodes/for_node"
|
|
10
|
+
require_relative "prompter_ruby/nodes/comment_node"
|
|
11
|
+
require_relative "prompter_ruby/nodes/raw_node"
|
|
12
|
+
require_relative "prompter_ruby/nodes/set_node"
|
|
9
13
|
require_relative "prompter_ruby/parser"
|
|
10
14
|
require_relative "prompter_ruby/template"
|
|
11
15
|
require_relative "prompter_ruby/library"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: prompter-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Johannes Dwi Cahyo
|
|
@@ -51,9 +51,13 @@ files:
|
|
|
51
51
|
- Rakefile
|
|
52
52
|
- lib/prompter_ruby.rb
|
|
53
53
|
- lib/prompter_ruby/errors.rb
|
|
54
|
+
- lib/prompter_ruby/filters.rb
|
|
54
55
|
- lib/prompter_ruby/library.rb
|
|
56
|
+
- lib/prompter_ruby/nodes/comment_node.rb
|
|
55
57
|
- lib/prompter_ruby/nodes/for_node.rb
|
|
56
58
|
- lib/prompter_ruby/nodes/if_node.rb
|
|
59
|
+
- lib/prompter_ruby/nodes/raw_node.rb
|
|
60
|
+
- lib/prompter_ruby/nodes/set_node.rb
|
|
57
61
|
- lib/prompter_ruby/nodes/text_node.rb
|
|
58
62
|
- lib/prompter_ruby/nodes/variable_node.rb
|
|
59
63
|
- lib/prompter_ruby/parser.rb
|