wml_action 0.0.2 → 0.0.3
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 +6 -14
- data/.rspec +0 -0
- data/README.md +25 -3
- data/features/wml_action.feature +27 -0
- data/lib/wml_action/expr.rb +74 -0
- data/lib/wml_action/lexer.rex +15 -1
- data/lib/wml_action/lexer.rex.rb +31 -1
- data/lib/wml_action/parser.tab.rb +219 -87
- data/lib/wml_action/parser.y +13 -0
- data/lib/wml_action/tag.rb +16 -0
- data/lib/wml_action/version.rb +1 -1
- data/lib/wml_action.rb +1 -0
- data/spec/document_spec.rb +7 -0
- data/spec/expr_spec.rb +89 -0
- data/spec/fixtures/expr.cfg +4 -0
- data/spec/tag_spec.rb +56 -28
- data/wml_action.gemspec +3 -2
- metadata +52 -30
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
MWJkMDEzZjY0YzBlY2JjMWU5YmM5OTgyNzJhMjFiYWY1NjdhMjEyZWYwN2Yx
|
10
|
-
MjBjMGM1OWRjZGYwMDM3MzA3MTQyOGEwOTU5ZDJmYjI4ODZjZGFkNTM1MTcz
|
11
|
-
YzEyNzA3NmEwYTA5YzIxZDBmNDgzYzI5Y2E0YWIwZGQwYWRjMGQ=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YTlhMjJiYTU0Njk3MmIzYzMxNDZiM2E3ODI2MTFmODA2Y2QxNDQ1MjAwNDhl
|
14
|
-
MTcyMTRlMzllYzZiM2Y2NGVhN2Q5ZGIyNjExMDQzNWU4MjIxYTM4MTZhNTkz
|
15
|
-
N2IyOWQ2OGYyZTA4ZjE4NjJlYzU5YzY5ODdjNGMwNzAzZWQxNTU=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a0364cfffffdced1188beb5f62ac2c5cf6eefee0
|
4
|
+
data.tar.gz: 17347228d19ffa2cc46569ece2bd5fff95e914be
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 05154a8857c5cf039180ee94aaf440148068564cf293d34ff4481eba76f1f4861ec086e3ece8b1a2d9b5b32ff1b7d2e1d8a41d45e89c1be9effc1b949405b4bb
|
7
|
+
data.tar.gz: e3d5376b9a88ba33f20ffd3c220e81bfc1b16633a9db492076578a4b8fd08e1684241c40810919a01162c0ccb950da757ee0606c4ff27a84179a7984cc5910b1
|
data/.rspec
ADDED
File without changes
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ WMLAction is WML parser and modifier. WML modifications described as simple exte
|
|
4
4
|
|
5
5
|
## Features
|
6
6
|
|
7
|
-
### Changing/adding attributes
|
7
|
+
### Changing/adding attributes
|
8
8
|
File:
|
9
9
|
```
|
10
10
|
[unit]
|
@@ -18,7 +18,7 @@ Modifications:
|
|
18
18
|
hp=25
|
19
19
|
race="human"
|
20
20
|
{REGENERATES}
|
21
|
-
[unit]
|
21
|
+
[/unit]
|
22
22
|
```
|
23
23
|
Becomes:
|
24
24
|
```
|
@@ -27,7 +27,7 @@ Becomes:
|
|
27
27
|
level=1
|
28
28
|
race="human"
|
29
29
|
{REGENERATES}
|
30
|
-
[unit]
|
30
|
+
[/unit]
|
31
31
|
```
|
32
32
|
### Adding tags
|
33
33
|
File:
|
@@ -86,6 +86,28 @@ Becomes:
|
|
86
86
|
[/unit]
|
87
87
|
```
|
88
88
|
|
89
|
+
### Expressions
|
90
|
+
File:
|
91
|
+
```
|
92
|
+
[unit]
|
93
|
+
hp=10
|
94
|
+
level=2
|
95
|
+
[/unit]
|
96
|
+
```
|
97
|
+
Modifications:
|
98
|
+
```
|
99
|
+
[unit]
|
100
|
+
hp=`(hp+level)*2`
|
101
|
+
[/unit]
|
102
|
+
```
|
103
|
+
Becomes:
|
104
|
+
```
|
105
|
+
[unit]
|
106
|
+
hp=24
|
107
|
+
level=2
|
108
|
+
[/unit]
|
109
|
+
```
|
110
|
+
|
89
111
|
## Installation
|
90
112
|
|
91
113
|
Add this line to your application's Gemfile:
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Feature: WMLAction
|
2
|
+
In order to keep my Wesnoth mod up to date
|
3
|
+
As a ERA author
|
4
|
+
I want to make quick modifications to many WML files
|
5
|
+
|
6
|
+
Scenario: Add and change attributes
|
7
|
+
Given a file named "attrs.cfg" with:
|
8
|
+
[unit]
|
9
|
+
hp=10
|
10
|
+
level=1
|
11
|
+
[/unit]
|
12
|
+
And a file named "attr_mod.cfg" with:
|
13
|
+
[unit]
|
14
|
+
hp=25
|
15
|
+
race="human"
|
16
|
+
{REGENERATES}
|
17
|
+
[unit]
|
18
|
+
When I run "wml_action modify attrs.cfg attr_mod.cfg"
|
19
|
+
Then the output should be:
|
20
|
+
[unit]
|
21
|
+
hp=25
|
22
|
+
level=1
|
23
|
+
race="human"
|
24
|
+
{REGENERATES}
|
25
|
+
[unit]
|
26
|
+
|
27
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module WMLAction
|
2
|
+
|
3
|
+
class Tag::Expr
|
4
|
+
|
5
|
+
attr_accessor :line
|
6
|
+
|
7
|
+
Var = Struct.new(:name) do
|
8
|
+
def to_s
|
9
|
+
name.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Op = Struct.new(:value) do
|
14
|
+
def to_s
|
15
|
+
value.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def initialize(elements)
|
21
|
+
@line = elements
|
22
|
+
end
|
23
|
+
|
24
|
+
def result(vars={})
|
25
|
+
return '' if @line.empty?
|
26
|
+
stack=[]
|
27
|
+
@line.each do |e|
|
28
|
+
case e
|
29
|
+
when Var then stack.push vars[e.name]
|
30
|
+
when Op then
|
31
|
+
x2 = stack.pop
|
32
|
+
x1 = stack.pop
|
33
|
+
raise SyntaxError.new("Invalid expression #{dump}, no values in stack") unless x1 && x2
|
34
|
+
case e.value
|
35
|
+
when '+' then stack.push(x1+x2)
|
36
|
+
when '-' then stack.push(x1-x2)
|
37
|
+
when '*' then stack.push(x1.to_f*x2)
|
38
|
+
when '/' then stack.push(x1.to_f/x2)
|
39
|
+
else raise NoMethodError.new("No such operation #{e.value}")
|
40
|
+
end
|
41
|
+
else stack.push e
|
42
|
+
end
|
43
|
+
end
|
44
|
+
raise SyntaxError.new("Invalid expression #{dump}, still have #{stack.size} values") unless stack.size == 1
|
45
|
+
return stack[0].to_i if stack[0].class==Float
|
46
|
+
return stack[0]
|
47
|
+
end
|
48
|
+
|
49
|
+
def ==(other)
|
50
|
+
@line==other.line
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
#TODO should revert to infix notation for file output
|
55
|
+
# needed to read outputted file
|
56
|
+
dump
|
57
|
+
end
|
58
|
+
|
59
|
+
def dump
|
60
|
+
@line.join(' ')
|
61
|
+
end
|
62
|
+
|
63
|
+
def <<(other)
|
64
|
+
@line=@line+other.line
|
65
|
+
return self
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.[](*elements)
|
69
|
+
new elements
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/lib/wml_action/lexer.rex
CHANGED
@@ -13,11 +13,13 @@ macro
|
|
13
13
|
CTAG /\[\/(\w+)\]/
|
14
14
|
ATTR /(\w+)=/
|
15
15
|
MACRO /\{.+\}/
|
16
|
-
ANUMBER /-?\d
|
16
|
+
ANUMBER /-?\d+(\.\d+)?/
|
17
17
|
ASTR /"[^"]*"/
|
18
18
|
APLAIN /.+/
|
19
19
|
SLASH /\//
|
20
20
|
COMMENT /\#.*$/
|
21
|
+
BACKQ /\`/
|
22
|
+
VAR /[\w]+/
|
21
23
|
|
22
24
|
BLANK /[ \t]+/
|
23
25
|
|
@@ -39,8 +41,20 @@ rule
|
|
39
41
|
:INATTR /#{MACRO}/ { [:AMACRO, text] }
|
40
42
|
:INATTR /_/ { [:UNDERSC, text] }
|
41
43
|
:INATTR /\+/ { [:APLUS, text] }
|
44
|
+
:INATTR /#{BACKQ}/ { @state = :INEXPR; [:BACKQ, text] }
|
42
45
|
:INATTR /#{APLAIN}/ { [:APLAIN, text] }
|
43
46
|
|
47
|
+
:INEXPR /#{BACKQ}/ { @state = nil; [:BACKQ, text] }
|
48
|
+
:INEXPR /\+/ { [:EPLUS,text] }
|
49
|
+
:INEXPR /\*/ { [:EMUL,text] }
|
50
|
+
:INEXPR /\// { [:EDIV,text] }
|
51
|
+
:INEXPR /\-/ { [:EMINUS,text] }
|
52
|
+
:INEXPR /\(/ { [text,text] }
|
53
|
+
:INEXPR /\)/ { [text,text] }
|
54
|
+
:INEXPR /#{ANUMBER}/ { [:ENUM,text.to_f] }
|
55
|
+
:INEXPR /#{ASTR}/ { [:ESTR,text] }
|
56
|
+
:INEXPR /#{VAR}/ { [:EVAR,text] }
|
57
|
+
|
44
58
|
/./
|
45
59
|
/\n/
|
46
60
|
|
data/lib/wml_action/lexer.rex.rb
CHANGED
@@ -16,11 +16,13 @@ class Parser < Racc::Parser
|
|
16
16
|
CTAG = /\[\/(\w+)\]/
|
17
17
|
ATTR = /(\w+)=/
|
18
18
|
MACRO = /\{.+\}/
|
19
|
-
ANUMBER = /-?\d
|
19
|
+
ANUMBER = /-?\d+(\.\d+)?/
|
20
20
|
ASTR = /"[^"]*"/
|
21
21
|
APLAIN = /.+/
|
22
22
|
SLASH = /\//
|
23
23
|
COMMENT = /\#.*$/
|
24
|
+
BACKQ = /\`/
|
25
|
+
VAR = /[\w]+/
|
24
26
|
BLANK = /[ \t]+/
|
25
27
|
|
26
28
|
class ScanError < StandardError ; end
|
@@ -110,12 +112,40 @@ class Parser < Racc::Parser
|
|
110
112
|
action { [:UNDERSC, text] }
|
111
113
|
when text = ss.scan(/\+/) then
|
112
114
|
action { [:APLUS, text] }
|
115
|
+
when text = ss.scan(/#{BACKQ}/) then
|
116
|
+
action { @state = :INEXPR; [:BACKQ, text] }
|
113
117
|
when text = ss.scan(/#{APLAIN}/) then
|
114
118
|
action { [:APLAIN, text] }
|
115
119
|
else
|
116
120
|
text = ss.string[ss.pos .. -1]
|
117
121
|
raise ScanError, "can not match (#{state.inspect}): '#{text}'"
|
118
122
|
end
|
123
|
+
when :INEXPR then
|
124
|
+
case
|
125
|
+
when text = ss.scan(/#{BACKQ}/) then
|
126
|
+
action { @state = nil; [:BACKQ, text] }
|
127
|
+
when text = ss.scan(/\+/) then
|
128
|
+
action { [:EPLUS,text] }
|
129
|
+
when text = ss.scan(/\*/) then
|
130
|
+
action { [:EMUL,text] }
|
131
|
+
when text = ss.scan(/\//) then
|
132
|
+
action { [:EDIV,text] }
|
133
|
+
when text = ss.scan(/\-/) then
|
134
|
+
action { [:EMINUS,text] }
|
135
|
+
when text = ss.scan(/\(/) then
|
136
|
+
action { [text,text] }
|
137
|
+
when text = ss.scan(/\)/) then
|
138
|
+
action { [text,text] }
|
139
|
+
when text = ss.scan(/#{ANUMBER}/) then
|
140
|
+
action { [:ENUM,text.to_f] }
|
141
|
+
when text = ss.scan(/#{ASTR}/) then
|
142
|
+
action { [:ESTR,text] }
|
143
|
+
when text = ss.scan(/#{VAR}/) then
|
144
|
+
action { [:EVAR,text] }
|
145
|
+
else
|
146
|
+
text = ss.string[ss.pos .. -1]
|
147
|
+
raise ScanError, "can not match (#{state.inspect}): '#{text}'"
|
148
|
+
end
|
119
149
|
else
|
120
150
|
raise ScanError, "undefined state: '#{state}'"
|
121
151
|
end # token = case state
|