landescape 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 22dbf4f4d4ebb551c726f65d7894706fd8e8cb7c
4
+ data.tar.gz: 5fad1bddcbfb7860b9eff86c48808e99fa934d7b
5
+ SHA512:
6
+ metadata.gz: cc43b68028b01c3d3229b75008430cc0d8ef2ed2e6733212bdbe31266214fe029d331142b6ab2f96b435cb2e1e9c22402bcdb18d3fe9921d80e71cd4bb51f54a
7
+ data.tar.gz: 2c498dc00f67c24cd5c92a8f722e6c6bacb0dd11d9b7f0da8c6b2a9387fc0b99e13be151b4635522e7fad85515be195a72af122205c7c01847ca112667db25c5
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in landescape.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 hibariya
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,86 @@
1
+ # Landescape
2
+
3
+ Landscape is a library for handling escape sequence.
4
+
5
+ ## Is It Good?
6
+
7
+ Yes. But Landescape has some problems for now.
8
+ **API will changed in future versions.**
9
+
10
+ Landescape doesn't support followings now:
11
+
12
+ * Coloring
13
+ * Any terminals except vt100
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'landescape'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install landescape
28
+
29
+ ## Usage
30
+
31
+ ### Tokenize, And convert to human readable statements
32
+
33
+ ```ruby
34
+ source = StringIO.new("\e[1mHello\e[m.") # IO like object
35
+
36
+ # tokenize
37
+ tokenizer = Landescape::Tokenizer.start(source)
38
+ tokens = tokenizer.result # => #<Queue:0x007ff0bc08f098 @que=["\e[1m", "H", "e", "l", "l", "o", "\e[m", "."], (snip...)>
39
+
40
+ # convert
41
+ converter = Landescape::Converter::VT100.start(tokens, non_block: true)
42
+ converter.result # => #<Queue:0x007ff0bc1cdc70 @que=[[:set_attributes, 1], [:print, "H"], [:print, "e"], [:print, "l"], [:print, "l"], [:print, "o"], [:exit_attribute_mode], [:print, "."]], (snip...)>
43
+ ```
44
+
45
+ ### Invoke shell on Curses window
46
+
47
+ ```ruby
48
+ require 'curses'
49
+ require 'pty'
50
+ require 'landescape'
51
+
52
+ Curses.noecho
53
+
54
+ window = Curses.stdscr
55
+ window.addstr 'Landescape example for curses'
56
+ window.refresh
57
+
58
+ terminal = window.subwin(27, 102, 10, 10)
59
+ terminal.scrollok true
60
+
61
+ PTY.getpty 'TERM=vt100 bash --noprofile' do |stdout, stdin, pid|
62
+ stdin.puts <<-SHELL
63
+ tput cols 100
64
+ tput lines 25
65
+ clear
66
+ SHELL
67
+
68
+ Thread.fork do
69
+ while char = terminal.getch
70
+ stdin.putc char
71
+ end
72
+ end
73
+
74
+ Landescape.run stdout, terminal
75
+
76
+ Curses.close_screen if Process.detach(pid).join
77
+ end
78
+ ```
79
+
80
+ ## Contributing
81
+
82
+ 1. Fork it
83
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
84
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
85
+ 4. Push to the branch (`git push origin my-new-feature`)
86
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new :spec
5
+
6
+ task default: :spec
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pty'
4
+ require 'curses'
5
+ require 'landescape'
6
+
7
+ Curses.noecho
8
+
9
+ window = Curses.stdscr
10
+ window.addstr 'Landescape example for curses'
11
+ window.refresh
12
+
13
+ terminal = window.subwin(27, 102, 10, 10)
14
+ terminal.scrollok true
15
+
16
+ PTY.getpty 'TERM=vt100 bash --noprofile' do |stdout, stdin, pid|
17
+ stdin.puts <<-SHELL
18
+ tput cols 100
19
+ tput lines 25
20
+ clear
21
+ SHELL
22
+
23
+ Thread.fork do
24
+ while char = terminal.getch
25
+ stdin.putc char
26
+ end
27
+ end
28
+
29
+ Landescape.run stdout, terminal
30
+
31
+ Curses.close_screen if Process.detach(pid).join
32
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'landescape/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'landescape'
9
+ spec.version = Landescape::VERSION
10
+ spec.authors = %w(hibariya)
11
+ spec.email = %w(celluloid.key@gmail.com)
12
+ spec.description = %(A library for handling escape sequence)
13
+ spec.summary = %(Handle escape sequence)
14
+ spec.homepage = 'https://github.com/hibariya/landescape'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = %w(lib examples)
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec'
25
+ end
@@ -0,0 +1,38 @@
1
+ require 'thread'
2
+ require 'landescape/version'
3
+
4
+ module Landescape
5
+ autoload :Tokenizer, 'landescape/tokenizer'
6
+ autoload :Converter, 'landescape/converter'
7
+ autoload :Evaluator, 'landescape/evaluator'
8
+
9
+ autoload :Curses, 'landescape/evaluator/curses'
10
+
11
+ class Nullogger
12
+ def method_missing(*); end
13
+ end
14
+
15
+ class << self
16
+ attr_writer :logger
17
+
18
+ def logger
19
+ @logger ||= Nullogger.new
20
+ end
21
+
22
+ def run(source, window, options = {})
23
+ options = {non_block: false, converter: Converter::VT100, evaluator: Curses}.merge(options)
24
+ converter_klass, evaluator_klass = [:converter, :evaluator].map {|n|
25
+ options.delete(n)
26
+ }
27
+
28
+ tokenizer = Tokenizer.start(source)
29
+ converter = converter_klass.start(tokenizer.result, options)
30
+
31
+ evaluator_klass.start(converter.result, window, options).tap {|evaluator|
32
+ at_exit do
33
+ [tokenizer, converter, evaluator].each &:stop
34
+ end
35
+ }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,124 @@
1
+ module Landescape
2
+ # Convert: ['\e[1;2f', 'H', 'i']] to [[:cursor_address, 1, 2], [:print, 'H'], [:print, 'i']]
3
+ module Converter
4
+ class Base
5
+ CODES = {}
6
+
7
+ class << self
8
+ def start(tokens, options = {})
9
+ new(tokens, options).tap(&:start)
10
+ end
11
+ end
12
+
13
+ attr_reader :tokens, :result
14
+
15
+ def initialize(tokens, options = {})
16
+ @options = {non_block: false}.merge(options)
17
+ @result = Queue.new
18
+ @tokens = tokens
19
+ end
20
+
21
+ def start
22
+ @convert_thread = Thread.fork {
23
+ loop do
24
+ token =
25
+ begin
26
+ tokens.shift(@options[:non_block])
27
+ rescue ThreadError
28
+ Thread.exit
29
+ end
30
+
31
+ _, detected = self.class::CODES.detect {|pattern, _| pattern === token }
32
+ match = Regexp.last_match
33
+ statement =
34
+ if detected
35
+ name, args_proc = detected.values_at(:name, :args)
36
+ args = args_proc ? args_proc.call(match.captures) : nil
37
+
38
+ Landescape.logger.debug %([statement] #{name}(#{Array(args).join(', ')}))
39
+ [name, *args]
40
+ else
41
+ Landescape.logger.debug %([statement] print(#{token.inspect}))
42
+ [:print, *token]
43
+ end
44
+
45
+ result.push statement
46
+ end
47
+ }
48
+ end
49
+
50
+ def stop
51
+ @convert_thread.exit if @convert_thread.alive?
52
+ end
53
+ end
54
+
55
+ class VT100 < Base
56
+ CODES = {
57
+ /^\e\[(\d+)?(?:;(\d+))?[Hf]$/ => {
58
+ name: :cursor_address,
59
+ args: ->(captures) { captures.map(&:to_i) }
60
+ },
61
+
62
+ /^\e\[(\d+)?A$/ => {
63
+ name: :cursor_up,
64
+ args: ->(captures) { captures.first.to_i }
65
+ },
66
+
67
+ /^\e\[(\d+)?B$/ => {
68
+ name: :cursor_down,
69
+ args: ->(captures) { captures.first.to_i }
70
+ },
71
+
72
+ /^\e\[(\d+)?C$/ => {
73
+ name: :cursor_right,
74
+ args: ->(captures) { captures.first.to_i }
75
+ },
76
+
77
+ /^\e\[(\d+)?D$/ => {
78
+ name: :cursor_left,
79
+ args: ->(captures) { captures.first.to_i }
80
+ },
81
+
82
+ /^\e\[0?m$/ => {name: :exit_attribute_mode},
83
+
84
+ /^\e\[([\d;]+)m$/ => {
85
+ name: :set_attributes,
86
+ args: ->(captures) { captures.join.split(/;/).map(&:to_i) }
87
+ },
88
+
89
+ /^\e\[(\d+);(\d+)r$/ => {
90
+ name: :change_scroll_region,
91
+ args: ->(captures) { captures.map(&:to_i) }
92
+ },
93
+
94
+ /^\e\[s$/ => {name: :save_cursor},
95
+ /^\e\[u$/ => {name: :restore_cursor},
96
+ /^\e\[2?J$/ => {name: :clear_screen},
97
+ /^\e\[K$/ => {name: :clear_eol},
98
+
99
+ /^\eD$/ => {name: :scroll_forward},
100
+ /^\eM$/ => {name: :scroll_reverse},
101
+
102
+ /^\e\[\?1h$/ => {name: :keypad_xmit},
103
+ /^\e\[\?1l$/ => {name: :keypad_local},
104
+
105
+ # cursor_normal is probably not available on vt100
106
+ /^\e\[\?25h$/ => {name: :cursor_visible},
107
+ /^\e\[\?25l$/ => {name: :cursor_invisible},
108
+
109
+ # backslashes
110
+ /^\n$/ => {name: :newline},
111
+ /^\r$/ => {name: :carriage_return},
112
+ /^(\a)$/ => {name: :bell},
113
+
114
+ # really...? maybe doubt!
115
+ /^\e\\$/ => {name: :carriage_return},
116
+
117
+ /^(\u000F|\e.+)$/ => {
118
+ name: :unknown,
119
+ args: ->(captures) { captures.first }
120
+ }
121
+ }
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,50 @@
1
+ module Landescape
2
+ module Evaluator
3
+ class Base
4
+ class << self
5
+ def start(statements, window, options = {})
6
+ new(statements, window, options).tap(&:start)
7
+ end
8
+ end
9
+
10
+ attr_reader :statements
11
+
12
+ def initialize(statements, window, options = {})
13
+ @options = {non_block: false}.merge(options)
14
+ @window = window
15
+ @statements = statements
16
+ end
17
+
18
+ def start
19
+ @eval_thread = Thread.fork {
20
+ loop do
21
+ name, *args =
22
+ begin
23
+ statements.shift(@options[:non_block])
24
+ rescue ThreadError
25
+ Thread.kill
26
+ end
27
+
28
+ if self.class.method_defined?(name)
29
+ __send__ name, *args
30
+ else
31
+ not_supported name, *args
32
+ end
33
+ end
34
+ }
35
+ end
36
+
37
+ def stop
38
+ @eval_thread.exit if @eval_thread.alive?
39
+ end
40
+
41
+ def unknown(token)
42
+ Landescape.logger.warn %([unknown] #{token.inspect})
43
+ end
44
+
45
+ def not_supported(name, *args)
46
+ Landescape.logger.warn %([not supported] #{name}(#{args.join(', ')}))
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,131 @@
1
+ require 'curses'
2
+ require 'landescape/evaluator'
3
+
4
+ module Landescape
5
+ module Evaluator
6
+ class Curses < Base
7
+ GRAPHICS_MODES = {
8
+ 1 => ::Curses::A_BOLD,
9
+ 4 => ::Curses::A_UNDERLINE,
10
+ 5 => ::Curses::A_BLINK,
11
+ 7 => ::Curses::A_REVERSE
12
+ }
13
+
14
+ attr_reader :window
15
+
16
+ def initialize(statements, window, options = {})
17
+ super
18
+
19
+ @saved_cursor = nil
20
+ @scroll_region = [0, window.maxy]
21
+ end
22
+
23
+ def print(str)
24
+ window.addstr str
25
+
26
+ window.refresh
27
+ end
28
+
29
+ def set_attributes(*modes)
30
+ return exit_attribute_mode if modes.empty?
31
+
32
+ modes.each do |mode|
33
+ if attr = GRAPHICS_MODES[mode]
34
+ window.attron attr
35
+ else
36
+ exit_attribute_mode
37
+ end
38
+ end
39
+ end
40
+
41
+ def exit_attribute_mode
42
+ window.attroff GRAPHICS_MODES.values.inject(:|)
43
+ end
44
+
45
+ def change_scroll_region(top, bottom)
46
+ @scroll_region = [top, bottom]
47
+
48
+ window.setscrreg *@scroll_region
49
+ end
50
+
51
+ def scroll_reverse
52
+ window.scrl -1
53
+ end
54
+
55
+ def scroll_forward
56
+ window.scrl 1
57
+ end
58
+
59
+ def cursor_address(line, column)
60
+ scroll_forward if line > window.cury && window.maxy.pred <= window.cury
61
+
62
+ window.setpos line, column
63
+ end
64
+
65
+ def newline
66
+ scroll_forward if window.cury == @scroll_region.last
67
+
68
+ cursor_address (window.cury.succ), 0
69
+ end
70
+
71
+ def carriage_return
72
+ cursor_address window.cury, 0
73
+ end
74
+
75
+ def cursor_up(step)
76
+ cursor_address (window.cury - step), window.curx
77
+ end
78
+
79
+ def cursor_down(step)
80
+ cursor_address (window.cury + step), window.curx
81
+ end
82
+
83
+ def cursor_right(step)
84
+ cursor_address window.cury, (window.curx + step)
85
+ end
86
+
87
+ def cursor_left(step)
88
+ cursor_address window.cury, (window.curx - step)
89
+ end
90
+
91
+ def save_cursor
92
+ @saved_cursor = [window.cury, window.curx]
93
+ end
94
+
95
+ def restore_cursor
96
+ cursor_address *@saved_cursor
97
+ end
98
+
99
+ def cursor_visible
100
+ window.curs_set 2
101
+ end
102
+
103
+ def cursor_invisible
104
+ window.curs_set 0
105
+ end
106
+
107
+ def keypad_xmit
108
+ window.keypad true
109
+ end
110
+
111
+ def keypad_local
112
+ window.keypad false
113
+ end
114
+
115
+ def clear_screen
116
+ cursor_address 0, 0
117
+
118
+ window.clear
119
+ window.refresh
120
+ end
121
+
122
+ def clear_eol
123
+ window.clrtoeol
124
+
125
+ window.refresh
126
+ end
127
+ end
128
+ end
129
+
130
+ Curses = Evaluator::Curses
131
+ end
@@ -0,0 +1,122 @@
1
+ module Landescape
2
+ # Tokenize: "\e[1;2fHi" to ['\e[1;2f', 'H', 'i']]
3
+ class Tokenizer
4
+ class << self
5
+ def start(source)
6
+ new(source).tap(&:start)
7
+ end
8
+ end
9
+
10
+ attr_reader :source, :result
11
+
12
+ def initialize(source)
13
+ @result = Queue.new
14
+ @source =
15
+ if source.respond_to?(:getc)
16
+ source
17
+ else
18
+ StringIO.new(source.to_s)
19
+ end
20
+
21
+ at_exit do
22
+ @source.close unless @source.closed?
23
+ end
24
+ end
25
+
26
+ def start
27
+ @tokenize_thread = Thread.fork {
28
+ while char = read_char
29
+ tokens =
30
+ case char
31
+ when nil then Thread.exit # StringIO#getc # => nil (EOF)
32
+ when /\e/ then escape char
33
+ else char
34
+ end
35
+
36
+ Array(tokens).each do |token|
37
+ result.push token
38
+ end
39
+ end
40
+ }
41
+ end
42
+
43
+ def stop
44
+ @tokenize_thread.exit if @tokenize_thread.alive?
45
+ end
46
+
47
+ private
48
+
49
+ def escape(token)
50
+ token << read_char
51
+
52
+ case token.chars.last
53
+ when /\[/
54
+ escape_code token
55
+ when /[()]/
56
+ escape_code_parens token
57
+ when /#/
58
+ escape_code_sharp token
59
+ when /\//
60
+ escape_code_slash token
61
+ when /[\da-zA-Z<=>_\\]/
62
+ token
63
+ else
64
+ fallback token
65
+ end
66
+ end
67
+
68
+ def escape_code(token)
69
+ token << read_char
70
+
71
+ case token.chars.last
72
+ when /[\d?;<=>]/
73
+ escape_code token
74
+ when /[a-zA-Z]/
75
+ token
76
+ else
77
+ fallback token
78
+ end
79
+ end
80
+
81
+ def escape_code_parens(token)
82
+ token << read_char
83
+
84
+ case token.chars.last
85
+ when /[\da-zA-Z]/
86
+ token
87
+ else
88
+ fallback token
89
+ end
90
+ end
91
+
92
+ def escape_code_sharp(token)
93
+ token << read_char
94
+
95
+ case token.chars.last
96
+ when /\d/
97
+ token
98
+ else
99
+ fallback token
100
+ end
101
+ end
102
+
103
+ def escape_code_slash(token)
104
+ token << read_char
105
+
106
+ case token.chars.last
107
+ when /[a-zA-Z]/
108
+ token
109
+ else
110
+ fallback token
111
+ end
112
+ end
113
+
114
+ def fallback(token)
115
+ token.chars
116
+ end
117
+
118
+ def read_char
119
+ source.getc
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,3 @@
1
+ module Landescape
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Landescape::Converter::VT100 do
4
+ def convert(tokens)
5
+ converter = Landescape::Converter::VT100.start(array_to_result(tokens), non_block: true)
6
+ convert_thread = converter.instance_variable_get(:@convert_thread)
7
+ convert_thread.join if convert_thread.alive?
8
+
9
+ result_to_array(converter.result)
10
+ end
11
+
12
+ it { convert(%W(\e[4m H i \e[m .)).should == [[:set_attributes, 4], [:print, 'H'], [:print, 'i'], [:exit_attribute_mode], [:print, '.']] }
13
+ it { convert(%W(\e[50;2H)).should == [[:cursor_address, 50, 2]] }
14
+ it { convert(%W(\e[5A)).should == [[:cursor_up, 5]] }
15
+ it { convert(%W(\e[5B)).should == [[:cursor_down, 5]] }
16
+ it { convert(%W(\e[5C)).should == [[:cursor_right, 5]] }
17
+ it { convert(%W(\e[5D)).should == [[:cursor_left, 5]] }
18
+ it { convert(%W(\e[1m)).should == [[:set_attributes, 1]] }
19
+ it { convert(%W(\e[1;20r)).should == [[:change_scroll_region, 1, 20]] }
20
+ it { convert(%W(\e[s)).should == [[:save_cursor]] }
21
+ it { convert(%W(\e[u)).should == [[:restore_cursor]] }
22
+ it { convert(%W(\e[2J)).should == [[:clear_screen]] }
23
+ it { convert(%W(\e[J)).should == [[:clear_screen]] }
24
+ it { convert(%W(\e[K)).should == [[:clear_eol]] }
25
+ it { convert(%W(\e[?1h)).should == [[:keypad_xmit]] }
26
+ it { convert(%W(\e[?1l)).should == [[:keypad_local]] }
27
+ it { convert(%W(\e[?25h)).should == [[:cursor_visible]] }
28
+ it { convert(%W(\e[?25l)).should == [[:cursor_invisible]] }
29
+ it { convert(%W(\n)).should == [[:newline]] }
30
+ it { convert(%W(\r)).should == [[:carriage_return]] }
31
+ it { convert(%W(\a)).should == [[:bell]] }
32
+ it { convert(%W(\e\\)).should == [[:carriage_return]] }
33
+ it { convert(%W(\u000F)).should == [[:unknown, "\u000F"]] }
34
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Landescape::Evaluator do
4
+ end
@@ -0,0 +1,12 @@
1
+ require 'landescape'
2
+ require 'support/example_helper'
3
+
4
+ RSpec.configure do |config|
5
+ config.treat_symbols_as_metadata_keys_with_true_values = true
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focus
8
+
9
+ config.order = 'random'
10
+
11
+ config.include ExampleHelper
12
+ end
@@ -0,0 +1,14 @@
1
+ module ExampleHelper
2
+ def array_to_result(a)
3
+ a.each.with_object(Queue.new) {|token, q|
4
+ q.push token
5
+ }
6
+ end
7
+
8
+ def result_to_array(q)
9
+ result_array = []
10
+ result_array << q.shift until q.empty?
11
+
12
+ result_array
13
+ end
14
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Landescape::Tokenizer do
4
+ def tokenize(str)
5
+ tokenizer = Landescape::Tokenizer.start(str)
6
+ tokenize_thread = tokenizer.instance_variable_get(:@tokenize_thread)
7
+ tokenize_thread.join if tokenize_thread.alive?
8
+
9
+ result_to_array(tokenizer.result)
10
+ end
11
+
12
+ it { tokenize("\e]***").should == %W(\e ] * * *) }
13
+ it { tokenize("Hi\e[32mHello\e[m").should == %W(H i \e[32m H e l l o \e[m) }
14
+ it { tokenize("\e[1;10H").should == %W(\e[1;10H) }
15
+ it { tokenize("\e[;H").should == %W(\e[;H) }
16
+ it { tokenize("\e[A").should == %W(\e[A) }
17
+ it { tokenize("\e[u").should == %W(\e[u) }
18
+ it { tokenize("\e[2J").should == %W(\e[2J) }
19
+ it { tokenize("\e[?1h").should == %W(\e[?1h) }
20
+
21
+ it { tokenize("\e(A\e)0").should == %W(\e\(A \e\)0) }
22
+ it { tokenize("\e#4").should == %W(\e#4) }
23
+ it { tokenize("\eB").should == %W(\eB) }
24
+ it { tokenize("\e<").should == %W(\e<) }
25
+ it { tokenize("\e>").should == %W(\e>) }
26
+ it { tokenize("\e=").should == %W(\e=) }
27
+ it { tokenize("\eD\eM").should == %W(\eD \eM) }
28
+ it { tokenize("\e\\").should == %W(\e\\) }
29
+
30
+ it { tokenize("\n\r").should == %W(\n \r) }
31
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: landescape
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - hibariya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A library for handling escape sequence
56
+ email:
57
+ - celluloid.key@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - examples/shell_on_curses.rb
69
+ - landescape.gemspec
70
+ - lib/landescape.rb
71
+ - lib/landescape/converter.rb
72
+ - lib/landescape/evaluator.rb
73
+ - lib/landescape/evaluator/curses.rb
74
+ - lib/landescape/tokenizer.rb
75
+ - lib/landescape/version.rb
76
+ - spec/converter_spec.rb
77
+ - spec/evaluator_spec.rb
78
+ - spec/spec_helper.rb
79
+ - spec/support/example_helper.rb
80
+ - spec/tokenizer_spec.rb
81
+ homepage: https://github.com/hibariya/landescape
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ - examples
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.1.10
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Handle escape sequence
106
+ test_files:
107
+ - spec/converter_spec.rb
108
+ - spec/evaluator_spec.rb
109
+ - spec/spec_helper.rb
110
+ - spec/support/example_helper.rb
111
+ - spec/tokenizer_spec.rb