alchemist-core 0.0.1
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 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/alchemist-core.gemspec +24 -0
- data/lib/alchemist-core.rb +6 -0
- data/lib/alchemist-core/version.rb +5 -0
- data/lib/alchemist/EastAsianWidth.txt +24466 -0
- data/lib/alchemist/event_machine/client_protocol.rb +166 -0
- data/lib/alchemist/glyphs.rb +88 -0
- data/lib/alchemist/unicode_monospace.rb +53 -0
- metadata +55 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
module Alchemist
|
2
|
+
module EventMachine
|
3
|
+
module ClientProtocol
|
4
|
+
# Clients should implement the various handle_* methods to
|
5
|
+
# take action in response to serve updates
|
6
|
+
#
|
7
|
+
def handle_welcome;end
|
8
|
+
def handle_hello;end
|
9
|
+
def handle_appeared;end
|
10
|
+
def handle_see(message);end
|
11
|
+
def handle_inventory(message);end
|
12
|
+
def handle_basics(message);end
|
13
|
+
def handle_compounds(message);end
|
14
|
+
def handle_messages(message);end
|
15
|
+
def handel_avatars(message);end
|
16
|
+
def handel_location(message);end
|
17
|
+
def handle_error(message);end
|
18
|
+
def handle_element(message);end
|
19
|
+
def handle_noelement(message);end
|
20
|
+
|
21
|
+
# Clients can call these methods to send commands to the server
|
22
|
+
#
|
23
|
+
def login(name)
|
24
|
+
send_data name
|
25
|
+
send_data "\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def appear
|
29
|
+
send_data "appear\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def request_location
|
33
|
+
send_data "location\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def look
|
37
|
+
send_data "look\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def read
|
41
|
+
send_data "read\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def request_inventory
|
45
|
+
send_data "inventory\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
def request_basics
|
49
|
+
send_data "basics\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
def request_compounds
|
53
|
+
send_data "compounds\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
def who
|
57
|
+
send_data "who\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
def move(direction)
|
61
|
+
send_data direction
|
62
|
+
send_data "\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
def north
|
66
|
+
move 'north'
|
67
|
+
end
|
68
|
+
|
69
|
+
def south
|
70
|
+
move 'south'
|
71
|
+
end
|
72
|
+
|
73
|
+
def east
|
74
|
+
move 'east'
|
75
|
+
end
|
76
|
+
|
77
|
+
def west
|
78
|
+
move 'west'
|
79
|
+
end
|
80
|
+
|
81
|
+
def put(element)
|
82
|
+
send_data "put #{element}\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
def create(element)
|
86
|
+
send_data "create #{element}\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
def element(symbol, name)
|
90
|
+
send_data "element #{symbol} #{name}\n"
|
91
|
+
end
|
92
|
+
|
93
|
+
def describe(symbol)
|
94
|
+
send_data "describe #{symbol}\n"
|
95
|
+
end
|
96
|
+
|
97
|
+
def forge(ingred_1, ingred_2, result)
|
98
|
+
send_data "forge #{ingred_1} #{ingred_2} #{result}\n"
|
99
|
+
end
|
100
|
+
|
101
|
+
def formulate(ingred_1, ingred_2, result, name)
|
102
|
+
send_data "formulate #{ingred_1} #{ingred_2} #{result} #{name}\n"
|
103
|
+
end
|
104
|
+
|
105
|
+
def message(number, string)
|
106
|
+
send_data "message #{name} #{string}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def take
|
110
|
+
send_data "take\n"
|
111
|
+
end
|
112
|
+
|
113
|
+
def receive_data(data)
|
114
|
+
@buffer ||= ''
|
115
|
+
@buffer << data
|
116
|
+
|
117
|
+
while @buffer =~ /^.*?\n/
|
118
|
+
line = $&
|
119
|
+
receive_line line
|
120
|
+
@buffer[0,line.length] = ''
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Command framing and dispatch
|
125
|
+
#
|
126
|
+
def receive_line(line)
|
127
|
+
if @lines_to_read
|
128
|
+
@response << line
|
129
|
+
@lines_to_read -= 1
|
130
|
+
|
131
|
+
if @lines_to_read <= 0
|
132
|
+
@lines_to_read = nil
|
133
|
+
dispatch_command @command, @response
|
134
|
+
@command = nil
|
135
|
+
@response = nil
|
136
|
+
end
|
137
|
+
elsif line =~ /^(see|messages|avatars) (\d+)$/
|
138
|
+
@command = $1
|
139
|
+
@lines_to_read = $2.to_i
|
140
|
+
@response = ''
|
141
|
+
else
|
142
|
+
dispatch_command *line.split(' ',2)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def dispatch_command(command, data = nil)
|
147
|
+
case command
|
148
|
+
when "Welcome" then handle_welcome
|
149
|
+
when "hello" then handle_hello
|
150
|
+
when "appeared" then handle_appeared
|
151
|
+
when "see" then handle_see data
|
152
|
+
when "inventory" then handle_inventory data
|
153
|
+
when "basics" then handle_basics data
|
154
|
+
when "compounds" then handle_compounds data
|
155
|
+
when "error" then handle_error data
|
156
|
+
when "messages" then handle_messages data
|
157
|
+
when "avatars" then handle_avatars data
|
158
|
+
when "location" then handle_location data
|
159
|
+
when "element" then handle_element data
|
160
|
+
when "noelement" then handle_noelement data
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Alchemist
|
2
|
+
module Glyphs
|
3
|
+
def self.strings
|
4
|
+
@chars ||= codes.map {|i| [i].pack("U*") }
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.codes
|
8
|
+
@codes ||= code_blocks.flat_map(&:to_a)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.code_blocks
|
12
|
+
@code_blocks ||= [
|
13
|
+
0x0021..0x0024,
|
14
|
+
0x0026..0x007e,
|
15
|
+
0x0100..0x0220,
|
16
|
+
0x0222..0x0233,
|
17
|
+
0x0250..0x02ad,
|
18
|
+
0x0374..0x0375,
|
19
|
+
0x037e..0x037e,
|
20
|
+
0x0384..0x038a,
|
21
|
+
0x038c..0x038c,
|
22
|
+
0x038e..0x03a1,
|
23
|
+
0x03a3..0x03ce,
|
24
|
+
0x03d0..0x03f6,
|
25
|
+
0x0400..0x0482,
|
26
|
+
0x0488..0x04ac,
|
27
|
+
0x04af..0x04ce,
|
28
|
+
0x04d0..0x04f5,
|
29
|
+
0x04f8..0x04f9,
|
30
|
+
0x0500..0x050f,
|
31
|
+
0x20a0..0x20b1,
|
32
|
+
0x2100..0x213a,
|
33
|
+
0x213d..0x214b,
|
34
|
+
0x2153..0x2183,
|
35
|
+
0x2190..0x21ff,
|
36
|
+
0x2200..0x22ff,
|
37
|
+
0x2300..0x23ce,
|
38
|
+
0x2460..0x24fe,
|
39
|
+
0x2500..0x257f,
|
40
|
+
0x2580..0x259f,
|
41
|
+
0x2600..0x2613,
|
42
|
+
0x2616..0x2617,
|
43
|
+
0x2619..0x267d,
|
44
|
+
0x2680..0x2689,
|
45
|
+
0x2701..0x2704,
|
46
|
+
0x2706..0x2709,
|
47
|
+
0x270c..0x2727,
|
48
|
+
0x2729..0x274b,
|
49
|
+
0x274d..0x274d,
|
50
|
+
0x274f..0x2752,
|
51
|
+
0x2756..0x2756,
|
52
|
+
0x2758..0x275e,
|
53
|
+
0x2761..0x2794,
|
54
|
+
0x2798..0x27af,
|
55
|
+
0x27b1..0x27bd,
|
56
|
+
0x27f0..0x27ff,
|
57
|
+
0x2800..0x28ff,
|
58
|
+
0x2900..0x297f,
|
59
|
+
0x2980..0x29ff,
|
60
|
+
0x2a00..0x2aff,
|
61
|
+
0x2e80..0x2e99,
|
62
|
+
0x2e9b..0x2ef3,
|
63
|
+
0x2f00..0x2fd5,
|
64
|
+
0x2ff0..0x2ffb,
|
65
|
+
0x3001..0x3020,
|
66
|
+
0x3030..0x303f,
|
67
|
+
0x3041..0x3054,
|
68
|
+
0x305b..0x3096,
|
69
|
+
0x309d..0x30ff,
|
70
|
+
0x3105..0x312c,
|
71
|
+
0x3131..0x318e,
|
72
|
+
0x3190..0x319f,
|
73
|
+
0x31a0..0x31b7,
|
74
|
+
0x3200..0x321c,
|
75
|
+
0x3220..0x3244,
|
76
|
+
0x3251..0x327b,
|
77
|
+
0x327f..0x32cb,
|
78
|
+
0x32d0..0x32fe,
|
79
|
+
0x3300..0x3377,
|
80
|
+
0x337b..0x33dd,
|
81
|
+
0x33e0..0x33fe,
|
82
|
+
0xa000..0xa48c,
|
83
|
+
0x4e00..0x9fff,
|
84
|
+
]
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Alchemist
|
2
|
+
module UnicodeMonospace
|
3
|
+
module StringExtensions
|
4
|
+
def pad_to_unicode_monospace
|
5
|
+
unpack('U*').flat_map do |c|
|
6
|
+
next c if c == "\n".ord
|
7
|
+
|
8
|
+
case UnicodeMonospace.east_asian_width(c)
|
9
|
+
when /^F|W$/ then c
|
10
|
+
else [c, ' '.ord]
|
11
|
+
end
|
12
|
+
end.pack('U*')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.east_asian_width(c)
|
17
|
+
east_asian_widths[c]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.east_asian_widths
|
21
|
+
@east_asian_widths ||= build_east_asian_widths
|
22
|
+
end
|
23
|
+
|
24
|
+
DATA_FILE = File.join(File.dirname(__FILE__), 'EastAsianWidth.txt')
|
25
|
+
|
26
|
+
def self.build_east_asian_widths
|
27
|
+
widths = {}
|
28
|
+
File.open(DATA_FILE) do |io|
|
29
|
+
io.each_line do |line|
|
30
|
+
next if line =~ /^#/
|
31
|
+
code_spec, width, _ = line.split(/;|#/)
|
32
|
+
|
33
|
+
codes = if code_spec =~ /\.\./
|
34
|
+
min,max = code_spec.split '..'
|
35
|
+
(min.to_i(16)..max.to_i(16)).to_a
|
36
|
+
else
|
37
|
+
[code_spec.to_i(16)]
|
38
|
+
end
|
39
|
+
|
40
|
+
codes.each do |code|
|
41
|
+
widths[code] = width && width.strip
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
widths
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
String.class_eval do
|
52
|
+
include Alchemist::UnicodeMonospace::StringExtensions
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: alchemist-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Vollbracht
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-17 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: See http://github.com/flipstone/alchemist-server
|
15
|
+
email:
|
16
|
+
- david.vollbracht@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- Rakefile
|
24
|
+
- alchemist-core.gemspec
|
25
|
+
- lib/alchemist-core.rb
|
26
|
+
- lib/alchemist-core/version.rb
|
27
|
+
- lib/alchemist/EastAsianWidth.txt
|
28
|
+
- lib/alchemist/event_machine/client_protocol.rb
|
29
|
+
- lib/alchemist/glyphs.rb
|
30
|
+
- lib/alchemist/unicode_monospace.rb
|
31
|
+
homepage: http://github.com/flipstone/alchemist-core
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project: alchemist-core
|
51
|
+
rubygems_version: 1.8.6
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Alchemist snippets useful for most clients
|
55
|
+
test_files: []
|