weskit 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|