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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NmFjMGE1ODU2Y2NkNTU3NDQyYTdjZDg5ZjUwYzExMWY2MjM4MTlkOA==
5
- data.tar.gz: !binary |-
6
- YjU4MjFiNjBiYjlmZWYzNTFkYmQ3NjAyNDE2ZTMyZDk5YzQxNGYwZQ==
7
- !binary "U0hBNTEy":
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
@@ -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
 
@@ -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