landescape 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.
@@ -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