weskit 0.0.2 → 0.1.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.
- data/.gitignore +4 -3
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -2
- data/LICENSE +339 -0
- data/README.md +135 -0
- data/Rakefile +4 -0
- data/lib/weskit/mp/adapter.rb +81 -0
- data/lib/weskit/mp/connection.rb +74 -0
- data/lib/weskit/mp/errors/error.rb +3 -0
- data/lib/weskit/mp/errors/response_error.rb +3 -0
- data/lib/weskit/mp/worker.rb +35 -0
- data/lib/weskit/mp.rb +13 -0
- data/lib/weskit/version.rb +1 -1
- data/lib/weskit/wml/attribute.rb +65 -0
- data/lib/weskit/wml/attributes.rb +16 -0
- data/lib/weskit/wml/builder.rb +66 -0
- data/lib/weskit/wml/element.rb +34 -0
- data/lib/weskit/wml/elements.rb +27 -0
- data/lib/weskit/wml/errors/error.rb +3 -0
- data/lib/weskit/wml/errors/invalid_identifier.rb +3 -0
- data/lib/weskit/wml/errors/invalid_item.rb +3 -0
- data/lib/weskit/wml/errors/invalid_option.rb +3 -0
- data/lib/weskit/wml/errors/invalid_parameters.rb +3 -0
- data/lib/weskit/wml/errors/parse_error.rb +3 -0
- data/lib/weskit/wml/errors/read_error.rb +3 -0
- data/lib/weskit/wml/extensions/object.rb +19 -0
- data/lib/weskit/wml/formatter.rb +82 -0
- data/lib/weskit/wml/formatters/ansi_color.rb +49 -0
- data/lib/weskit/wml/formatters/ansi_color_attribute.rb +31 -0
- data/lib/weskit/wml/formatters/ansi_color_element.rb +22 -0
- data/lib/weskit/wml/formatters/attribute.rb +62 -0
- data/lib/weskit/wml/formatters/element.rb +44 -0
- data/lib/weskit/wml/formatters/item_formatter.rb +17 -0
- data/lib/weskit/wml/grammars/wml.treetop +195 -0
- data/lib/weskit/wml/item.rb +89 -0
- data/lib/weskit/wml/items.rb +29 -0
- data/lib/weskit/wml/mixins/container.rb +96 -0
- data/lib/weskit/wml/mixins/grammar.rb +17 -0
- data/lib/weskit/wml/mixins/searchable.rb +43 -0
- data/lib/weskit/wml/mixins/validator.rb +29 -0
- data/lib/weskit/wml/parser.rb +47 -0
- data/lib/weskit/wml/root.rb +17 -0
- data/lib/weskit/wml/wml.rb +1580 -0
- data/lib/weskit/wml.rb +12 -6
- data/lib/weskit.rb +2 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/wml/attribute_spec.rb +51 -0
- data/spec/wml/attributes_spec.rb +19 -0
- data/spec/wml/builder_spec.rb +52 -0
- data/spec/wml/element_spec.rb +20 -0
- data/spec/wml/elements_spec.rb +25 -0
- data/spec/wml/formatter_spec.rb +42 -0
- data/spec/wml/item_spec.rb +25 -0
- data/spec/wml/items_spec.rb +15 -0
- data/spec/wml/parser_spec.rb +60 -0
- data/spec/wml/root_spec.rb +15 -0
- data/spec/wml_helpers.rb +40 -0
- data/spec/wml_matchers.rb +17 -0
- data/spec/wml_shared_examples.rb +68 -0
- data/spec/wml_spec_helper.rb +5 -0
- data/weskit.gemspec +8 -5
- metadata +192 -50
- data/README +0 -2
- data/lib/weskit/lobby/bot.rb +0 -85
- data/lib/weskit/lobby/bot_error.rb +0 -3
- data/lib/weskit/lobby.rb +0 -11
- data/lib/weskit/wml/node.rb +0 -76
- data/lib/weskit/wml/node_array.rb +0 -25
- data/lib/weskit/wml/node_error.rb +0 -3
- data/lib/weskit/wml/reader.rb +0 -67
- data/lib/weskit/wml/reader_error.rb +0 -3
- data/lib/weskit/wml/string_extensions.rb +0 -59
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'treetop'
|
2
|
+
require 'weskit/wml'
|
3
|
+
|
4
|
+
grammar WesnothMarkupLanguage
|
5
|
+
rule document
|
6
|
+
contents {
|
7
|
+
def wml
|
8
|
+
::Weskit::WML::Root.new.push *::Weskit::WML::Mixins::Grammar.reject_non_wml(elements)
|
9
|
+
end
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
# parts -------------------------------------------------------------------------------
|
14
|
+
|
15
|
+
rule identifier
|
16
|
+
[a-z] [a-z_]* {
|
17
|
+
def name
|
18
|
+
text_value
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
rule raw_string
|
24
|
+
(!eol .)* {
|
25
|
+
def data
|
26
|
+
text_value
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
rule code_content
|
32
|
+
(!'>>' content)* {
|
33
|
+
def contents
|
34
|
+
text_value
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
rule code_string
|
40
|
+
'<<' string:code_content '>>' {
|
41
|
+
def data
|
42
|
+
string.contents
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
rule multiline_content
|
48
|
+
(!quote content)* {
|
49
|
+
def contents
|
50
|
+
text_value
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
rule multiline_string
|
56
|
+
(quote string:multiline_content quote)* {
|
57
|
+
def data
|
58
|
+
elements.collect(&:string).collect(&:contents).join '"'
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
rule translatable_string
|
64
|
+
'_' lws string:multiline_string {
|
65
|
+
def data
|
66
|
+
string.contents
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
rule opening_tag
|
72
|
+
lws '[' tag:identifier ']' fws {
|
73
|
+
def name
|
74
|
+
tag.name
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
rule amending_tag
|
80
|
+
lws '[+' tag:identifier ']' fws {
|
81
|
+
def name
|
82
|
+
tag.name
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
rule closing_tag
|
88
|
+
lws '[/' tag:identifier ']' fws {
|
89
|
+
def name
|
90
|
+
tag.name
|
91
|
+
end
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
rule blank_line
|
96
|
+
ws* "\n"
|
97
|
+
end
|
98
|
+
|
99
|
+
rule item
|
100
|
+
code_attribute / multiline_attribute / translatable_attribute / attribute / amending_element / element
|
101
|
+
end
|
102
|
+
|
103
|
+
rule contents
|
104
|
+
(blank_line / item)* {
|
105
|
+
def items
|
106
|
+
::Weskit::WML::Mixins::Grammar.reject_non_wml elements
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
# items -------------------------------------------------------------------------------
|
112
|
+
|
113
|
+
rule attribute
|
114
|
+
lws id:identifier lws equals value:raw_string eol {
|
115
|
+
def item
|
116
|
+
::Weskit::WML::Attribute.new id.name, value.data
|
117
|
+
end
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
rule code_attribute
|
122
|
+
lws id:identifier lws equals lws value:code_string fws {
|
123
|
+
def item
|
124
|
+
::Weskit::WML::Attribute.new id.name, value.data, :code => true
|
125
|
+
end
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
rule multiline_attribute
|
130
|
+
lws id:identifier lws equals lws value:multiline_string fws {
|
131
|
+
def item
|
132
|
+
::Weskit::WML::Attribute.new id.name, value.data
|
133
|
+
end
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
rule translatable_attribute
|
138
|
+
lws id:identifier lws equals lws '_' lws value:multiline_string fws {
|
139
|
+
def item
|
140
|
+
::Weskit::WML::Attribute.new id.name, value.data, :translatable => true
|
141
|
+
end
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
145
|
+
rule element
|
146
|
+
open:opening_tag nested:contents close:closing_tag {
|
147
|
+
def item
|
148
|
+
::Weskit::WML::Mixins::Grammar.raise_on_mismatching open, close
|
149
|
+
::Weskit::WML::Element.new(open.name).push *nested.items
|
150
|
+
end
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
rule amending_element
|
155
|
+
open:amending_tag nested:contents close:closing_tag {
|
156
|
+
def item
|
157
|
+
::Weskit::WML::Mixins::Grammar.raise_on_mismatching open, close
|
158
|
+
::Weskit::WML::Element.new(open.name, :amendment => true).push *nested.items
|
159
|
+
end
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
# helpers -----------------------------------------------------------------------------
|
164
|
+
|
165
|
+
rule content
|
166
|
+
"\n" / .
|
167
|
+
end
|
168
|
+
|
169
|
+
rule eol
|
170
|
+
"\n" / !.
|
171
|
+
end
|
172
|
+
|
173
|
+
rule equals
|
174
|
+
'='
|
175
|
+
end
|
176
|
+
|
177
|
+
rule quote
|
178
|
+
'"'
|
179
|
+
end
|
180
|
+
|
181
|
+
# whitespace
|
182
|
+
rule ws
|
183
|
+
"\s" / "\t"
|
184
|
+
end
|
185
|
+
|
186
|
+
# leading whitespaces
|
187
|
+
rule lws
|
188
|
+
ws*
|
189
|
+
end
|
190
|
+
|
191
|
+
# following whitespaces
|
192
|
+
rule fws
|
193
|
+
ws* eol
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Weskit::WML
|
2
|
+
class Item
|
3
|
+
include Comparable, Mixins::Validator
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def <=> other
|
8
|
+
case other
|
9
|
+
when self.class then "#{name}" <=> "#{other.name}"
|
10
|
+
when Item then "#{self.class}" <=> "#{other.class}"
|
11
|
+
else nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def formatter= item
|
16
|
+
raise_unless Formatter, item
|
17
|
+
@formatter = item
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize name, defaults = {}
|
21
|
+
self.name = name
|
22
|
+
merge defaults
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge options = {}
|
26
|
+
raise_unless Hash, options
|
27
|
+
|
28
|
+
options.each do |option, value|
|
29
|
+
raise_if_missing self, option
|
30
|
+
send "#{option}=", value
|
31
|
+
end
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def name= name
|
37
|
+
raise_if_invalid name
|
38
|
+
@name = Item.identifier name
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
formatter.format_detached self
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :to_str, :to_s
|
46
|
+
|
47
|
+
class << self
|
48
|
+
def identifier name
|
49
|
+
"#{name}".to_sym
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def attachable_to name
|
55
|
+
class_eval <<-code
|
56
|
+
attr_reader :#{name}
|
57
|
+
|
58
|
+
def #{name}= item
|
59
|
+
raise_unless Element, item
|
60
|
+
@#{name} = item
|
61
|
+
end
|
62
|
+
|
63
|
+
def #{name}?
|
64
|
+
!!#{name}
|
65
|
+
end
|
66
|
+
|
67
|
+
alias_method :attach_to, :#{name}=
|
68
|
+
|
69
|
+
def detach
|
70
|
+
if #{name}?
|
71
|
+
@#{name}.delete self
|
72
|
+
@#{name} = nil
|
73
|
+
end
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def distance
|
78
|
+
#{name} ? #{name}.distance + 1 : 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def formatter
|
82
|
+
current_formatter = @formatter || Formatter.default
|
83
|
+
#{name} ? #{name}.formatter : current_formatter
|
84
|
+
end
|
85
|
+
code
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Weskit::WML
|
2
|
+
class Items
|
3
|
+
include Enumerable, Mixins::Container, Mixins::Validator
|
4
|
+
|
5
|
+
attr_reader :contents
|
6
|
+
|
7
|
+
def formatter
|
8
|
+
@formatter or Formatter.default
|
9
|
+
end
|
10
|
+
|
11
|
+
def formatter= item
|
12
|
+
raise_unless Formatter, item
|
13
|
+
@formatter = item
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize *items
|
17
|
+
@contents = []
|
18
|
+
push *items
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
@contents.collect do |item|
|
23
|
+
formatter.format_detached item, formatter
|
24
|
+
end.join formatter.separator
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :to_str, :to_s
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Weskit::WML::Mixins
|
4
|
+
module Container
|
5
|
+
extend Forwardable
|
6
|
+
include ::Weskit::WML::Mixins::Validator
|
7
|
+
|
8
|
+
def_delegators :contents, :each, :empty?, :first, :last, :size, :to_a
|
9
|
+
|
10
|
+
def [] key
|
11
|
+
case key
|
12
|
+
when Integer then elements[key]
|
13
|
+
else attributes[key] rescue nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def << item
|
18
|
+
raise_unless ::Weskit::WML::Item, item
|
19
|
+
add item
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def attributes
|
24
|
+
::Weskit::WML::Attributes.new *(select_type_of ::Weskit::WML::Attribute)
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :attrs, :attributes
|
28
|
+
|
29
|
+
def build &contents
|
30
|
+
push *(::Weskit::WML::Builder.build &contents)
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete item
|
34
|
+
contents.delete_if {|i| i.equal? item}
|
35
|
+
end
|
36
|
+
|
37
|
+
def elements
|
38
|
+
::Weskit::WML::Elements.new *(select_type_of ::Weskit::WML::Element)
|
39
|
+
end
|
40
|
+
|
41
|
+
alias_method :elems, :elements
|
42
|
+
|
43
|
+
def exists? item
|
44
|
+
contents.any? {|i| i.equal? item}
|
45
|
+
end
|
46
|
+
|
47
|
+
def push *items
|
48
|
+
items.each {|i| self << i}
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def add item
|
55
|
+
return nil if exists? item
|
56
|
+
|
57
|
+
case item
|
58
|
+
when ::Weskit::WML::Attribute then append_attribute item
|
59
|
+
else contents << item
|
60
|
+
end
|
61
|
+
|
62
|
+
item
|
63
|
+
end
|
64
|
+
|
65
|
+
def append item
|
66
|
+
raise_unless ::Weskit::WML::Element, item
|
67
|
+
find(item.name, false).last.push(*item.contents) rescue nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def append_attribute item
|
71
|
+
raise_unless ::Weskit::WML::Attribute, item
|
72
|
+
index = attribute_index item
|
73
|
+
index ? contents[index] = item : contents << item
|
74
|
+
end
|
75
|
+
|
76
|
+
def attribute name
|
77
|
+
name = ::Weskit::WML::Item.identifier name
|
78
|
+
contents.detect do |item|
|
79
|
+
item.is_a? ::Weskit::WML::Attribute and item.name == name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def attribute_index item
|
84
|
+
contents.find_index {|i| i == item}
|
85
|
+
end
|
86
|
+
|
87
|
+
def attribute_value name
|
88
|
+
found = attribute name
|
89
|
+
found ? found.value : nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def select_type_of constant
|
93
|
+
contents.select {|i| i.is_a? constant}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Weskit::WML::Mixins
|
2
|
+
module Grammar
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def raise_on_mismatching opening, closing
|
6
|
+
unless opening.name == closing.name
|
7
|
+
raise ::Weskit::WML::Errors::ParseError, 'Invalid element'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def reject_non_wml elements
|
12
|
+
elements.reduce(Array.new) do |array, element|
|
13
|
+
array << element.item if element.respond_to? :item ; array
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Weskit::WML::Mixins
|
2
|
+
module Searchable
|
3
|
+
def find_recursively &criteria
|
4
|
+
::Weskit::WML::Elements.new *elements_recursively.select(&criteria)
|
5
|
+
end
|
6
|
+
|
7
|
+
def elements_recursively
|
8
|
+
element_contents + element_contents.reduce(Array.new) do |r, i|
|
9
|
+
r + i.elements_recursively
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def append item
|
16
|
+
find_elements(item.name, false).last.push(*item.contents) rescue nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def append? item
|
20
|
+
item.is_a? ::Weskit::WML::Element and item.amendment?
|
21
|
+
end
|
22
|
+
|
23
|
+
def base nested
|
24
|
+
nested ? nested_contents : contents
|
25
|
+
end
|
26
|
+
|
27
|
+
def element_contents
|
28
|
+
contents.select {|i| i.is_a? ::Weskit::WML::Element}
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_elements name, nested = false
|
32
|
+
name = ::Weskit::WML::Item.identifier name
|
33
|
+
found = base(nested).select {|i| i.is_a? ::Weskit::WML::Element and i.name == name}
|
34
|
+
::Weskit::WML::Elements.new *found
|
35
|
+
end
|
36
|
+
|
37
|
+
def nested_contents
|
38
|
+
contents.reduce(Array.new) do |r, i|
|
39
|
+
r + i.contents
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Weskit::WML::Mixins
|
2
|
+
module Validator
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def raise_unless type, item
|
6
|
+
unless item.is_a? type
|
7
|
+
raise ::Weskit::WML::Errors::InvalidItem, "Invalid #{type}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def raise_if_invalid identifier
|
12
|
+
unless "#{identifier}".match identifier_pattern
|
13
|
+
raise ::Weskit::WML::Errors::InvalidIdentifier, "Invalid identifier"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def raise_if_missing object, method
|
18
|
+
unless object.respond_to? "#{method}="
|
19
|
+
raise ::Weskit::WML::Errors::InvalidOption, "Object doesn't have #{method}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def identifier_pattern
|
26
|
+
%r{^[a-z][a-z_0-9]*$}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'polyglot'
|
2
|
+
require 'treetop'
|
3
|
+
|
4
|
+
require 'open-uri'
|
5
|
+
require 'stringio'
|
6
|
+
require 'zlib'
|
7
|
+
|
8
|
+
module Weskit::WML
|
9
|
+
class Parser
|
10
|
+
private_class_method :new
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def string str
|
14
|
+
parse str
|
15
|
+
end
|
16
|
+
|
17
|
+
def uri uri
|
18
|
+
begin
|
19
|
+
str = open(uri).read
|
20
|
+
rescue
|
21
|
+
raise Errrors::ReadError, "Coldn't open URI"
|
22
|
+
ensure
|
23
|
+
str = Zlib::GzipReader.new(StringIO.new str).read rescue str
|
24
|
+
end
|
25
|
+
|
26
|
+
parse str
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse data
|
32
|
+
parsed = parser.parse data.strip, :consume_all_input => false
|
33
|
+
|
34
|
+
unless parsed
|
35
|
+
msg = parser.failure_reason or 'Invalid data'
|
36
|
+
raise Errors::ParseError, msg
|
37
|
+
end
|
38
|
+
|
39
|
+
parsed.wml
|
40
|
+
end
|
41
|
+
|
42
|
+
def parser
|
43
|
+
@parser ||= WesnothMarkupLanguageParser.new
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Weskit::WML
|
2
|
+
class Root < Items
|
3
|
+
include Mixins::Searchable, Mixins::Validator
|
4
|
+
|
5
|
+
def << item
|
6
|
+
raise_unless Item, item
|
7
|
+
(append? item) ? append(item) : add(item)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def find name, nested = false
|
12
|
+
find_elements name, nested
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :method_missing, :find
|
16
|
+
end
|
17
|
+
end
|