spacy 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.gitmodules +12 -0
- data/ChangeLog +3 -0
- data/Gemfile +35 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/bin/spacy +14 -0
- data/lib/spacy.rb +10 -0
- data/lib/spacy/application.rb +27 -0
- data/lib/spacy/extensions.rb +10 -0
- data/lib/spacy/key.rb +53 -0
- data/lib/spacy/keymap.rb +43 -0
- data/lib/spacy/keystroke.rb +40 -0
- data/lib/spacy/module.rb +45 -0
- data/lib/spacy/text.rb +101 -0
- data/lib/spacy/textbuffer.rb +160 -0
- data/lib/spacy/textline.rb +73 -0
- data/lib/spacy/window.rb +91 -0
- data/spacy.gemspec +44 -0
- data/task/mac.rake +45 -0
- data/task/submodule.rake +39 -0
- data/test/helpers.rb +10 -0
- data/test/test_text.rb +43 -0
- data/test/test_textbuffer.rb +84 -0
- data/test/test_textline.rb +56 -0
- metadata +175 -0
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/ChangeLog
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
|
7
|
+
SUBMODULES = %w[xot rucy rays reflexion]
|
8
|
+
|
9
|
+
|
10
|
+
def local_path (name)
|
11
|
+
File.expand_path "../#{name.gsub /xion/, 'x'}", __FILE__
|
12
|
+
end
|
13
|
+
|
14
|
+
def have_local (name)
|
15
|
+
File.directory? local_path name
|
16
|
+
end
|
17
|
+
|
18
|
+
def submodule (*names)
|
19
|
+
names.each do |name|
|
20
|
+
if have_local name
|
21
|
+
gem name, path: local_path(name)
|
22
|
+
else
|
23
|
+
gem name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
group :development do
|
30
|
+
gem 'rake'
|
31
|
+
end
|
32
|
+
|
33
|
+
submodule *SUBMODULES
|
34
|
+
|
35
|
+
gem 'spacy', path: '.' if SUBMODULES.all? {|name| have_local name}
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'spacy/module'
|
6
|
+
|
7
|
+
|
8
|
+
MODULE = Spacy
|
9
|
+
SUBMODULES = %w[xot rucy rays reflex]
|
10
|
+
TASKS = %w[git gem test submodule mac]
|
11
|
+
|
12
|
+
|
13
|
+
begin
|
14
|
+
|
15
|
+
require 'xot/rake'
|
16
|
+
require 'xot/module'
|
17
|
+
require 'rucy/module'
|
18
|
+
require 'rays/module'
|
19
|
+
require 'reflex/module'
|
20
|
+
|
21
|
+
rescue LoadError
|
22
|
+
|
23
|
+
load 'task/submodule.rake'
|
24
|
+
|
25
|
+
task :default => 'submodule:init'
|
26
|
+
|
27
|
+
else
|
28
|
+
|
29
|
+
include Xot::Rake
|
30
|
+
|
31
|
+
task :default => :status
|
32
|
+
|
33
|
+
task :build => :app
|
34
|
+
|
35
|
+
task :run => :build
|
36
|
+
|
37
|
+
[Xot, Rucy, Rays, Reflex, Spacy].each {|m| m.load_tasks *TASKS}
|
38
|
+
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.4
|
data/bin/spacy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/Users/snori/.rvm/rubies/ruby-1.9.2-p180/bin/ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
3
|
+
|
4
|
+
|
5
|
+
(%w[xot rays reflex].product(%w[ext lib]) + [["lib"]]).each do |paths|
|
6
|
+
root = (__FILE__ =~ /\/Spacy.app\// ? "../../.." : "..").split('/')
|
7
|
+
$: << File.expand_path(File.join File.dirname(__FILE__), *root, *paths)
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'spacy'
|
12
|
+
|
13
|
+
|
14
|
+
Spacy::Application.new.run
|
data/lib/spacy.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
require 'reflex/autoinit'
|
5
|
+
require 'reflex/reflex'
|
6
|
+
require 'spacy/window'
|
7
|
+
|
8
|
+
|
9
|
+
module Spacy
|
10
|
+
|
11
|
+
|
12
|
+
class Application < Reflex::Application
|
13
|
+
|
14
|
+
def initialize ()
|
15
|
+
super :name => 'Spacy'
|
16
|
+
@window = Window.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def run ()
|
20
|
+
@window.show
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
end # Application
|
25
|
+
|
26
|
+
|
27
|
+
end # Spacy
|
data/lib/spacy/key.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Spacy
|
5
|
+
|
6
|
+
|
7
|
+
class Key
|
8
|
+
|
9
|
+
include Comparable
|
10
|
+
|
11
|
+
attr_reader :key, :shift, :ctrl, :alt
|
12
|
+
|
13
|
+
def initialize (key, shift = false, ctrl = false, alt = false)
|
14
|
+
@key, @shift, @ctrl, @alt = key.to_sym, shift, ctrl, alt
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s ()
|
18
|
+
s = ''
|
19
|
+
s << '/' if @alt
|
20
|
+
s << '^' if @ctrl
|
21
|
+
s << @key
|
22
|
+
s
|
23
|
+
end
|
24
|
+
|
25
|
+
def << (key)
|
26
|
+
raise ArgumentError unless key.kind_of? Key
|
27
|
+
KeyStroke.new << self << key
|
28
|
+
end
|
29
|
+
|
30
|
+
def hash ()
|
31
|
+
to_s.hash
|
32
|
+
end
|
33
|
+
|
34
|
+
def eql? (obj)
|
35
|
+
to_s == obj.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def <=> (obj)
|
39
|
+
to_s <=> obj.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def inspect ()
|
43
|
+
mods = ''
|
44
|
+
mods << ', shift' if @shift
|
45
|
+
mods << ', ctrl' if @ctrl
|
46
|
+
mods << ', alt' if @alt
|
47
|
+
"#<Spacy::Key '#{@key.to_s}#{mods}'>"
|
48
|
+
end
|
49
|
+
|
50
|
+
end# Key
|
51
|
+
|
52
|
+
|
53
|
+
end # Spacy
|
data/lib/spacy/keymap.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Spacy
|
5
|
+
|
6
|
+
|
7
|
+
class KeyMap
|
8
|
+
|
9
|
+
def initialize ()
|
10
|
+
@map = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def add (key, &proc)
|
14
|
+
@map[key] = proc
|
15
|
+
end
|
16
|
+
|
17
|
+
def remove (key)
|
18
|
+
@map.delete key
|
19
|
+
end
|
20
|
+
|
21
|
+
def key_down (key, repeat)
|
22
|
+
proc = @map[key]
|
23
|
+
proc.call key if proc
|
24
|
+
end
|
25
|
+
|
26
|
+
def key_up (key)
|
27
|
+
end
|
28
|
+
|
29
|
+
def key_press (chars)
|
30
|
+
end
|
31
|
+
|
32
|
+
def [] (key)
|
33
|
+
@map[key]
|
34
|
+
end
|
35
|
+
|
36
|
+
def []= (key, proc)
|
37
|
+
@map[key] = proc
|
38
|
+
end
|
39
|
+
|
40
|
+
end# KeyMap
|
41
|
+
|
42
|
+
|
43
|
+
end # Spacy
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Spacy
|
5
|
+
|
6
|
+
|
7
|
+
class KeyStroke
|
8
|
+
|
9
|
+
include Comparable
|
10
|
+
|
11
|
+
def initialize ()
|
12
|
+
@keys = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s ()
|
16
|
+
@keys.join
|
17
|
+
end
|
18
|
+
|
19
|
+
def push (key)
|
20
|
+
@keys << key
|
21
|
+
end
|
22
|
+
|
23
|
+
alias << push
|
24
|
+
|
25
|
+
def hash ()
|
26
|
+
to_s.hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def eql? (obj)
|
30
|
+
to_s == obj.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def <=> (obj)
|
34
|
+
to_s <=> obj.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
end# KeyStroke
|
38
|
+
|
39
|
+
|
40
|
+
end # Spacy
|
data/lib/spacy/module.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Spacy
|
5
|
+
|
6
|
+
|
7
|
+
extend module ClassMethods
|
8
|
+
|
9
|
+
def root_dir ()
|
10
|
+
File.expand_path(File.join File.dirname(__FILE__), '..', '..')
|
11
|
+
end
|
12
|
+
|
13
|
+
def include_dirs ()
|
14
|
+
[File.join(root_dir, 'include')]
|
15
|
+
end
|
16
|
+
|
17
|
+
def library_dirs ()
|
18
|
+
%w[lib].map {|dir| File.join root_dir, dir}
|
19
|
+
end
|
20
|
+
|
21
|
+
def task_dir ()
|
22
|
+
File.join root_dir, 'task'
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_tasks (*names)
|
26
|
+
if names.empty?
|
27
|
+
Dir["#{task_dir}/**/*.rake"].each {|path| load path}
|
28
|
+
else
|
29
|
+
names.each do |name|
|
30
|
+
path = "#{task_dir}/#{name}.rake"
|
31
|
+
load path if File.exist? path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def version ()
|
37
|
+
open(File.join root_dir, 'VERSION') {|f| f.readline.chomp}
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
|
42
|
+
end# ClassMethods
|
43
|
+
|
44
|
+
|
45
|
+
end# Spacy
|
data/lib/spacy/text.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
require 'forwardable'
|
5
|
+
require 'spacy/textbuffer'
|
6
|
+
|
7
|
+
|
8
|
+
module Spacy
|
9
|
+
|
10
|
+
|
11
|
+
class Text
|
12
|
+
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
attr_reader :buffer
|
16
|
+
|
17
|
+
def_delegators :@buffer,
|
18
|
+
:each, :last, :nrow, :ncolumn, :to_a, :to_s,
|
19
|
+
:[], :[]=
|
20
|
+
|
21
|
+
def initialize (arg = nil)
|
22
|
+
@buffer = (TextBuffer === arg) ? arg : TextBuffer.new(arg)
|
23
|
+
@first = @last = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def pos ()
|
27
|
+
@first
|
28
|
+
end
|
29
|
+
|
30
|
+
def pos= (n)
|
31
|
+
last = @buffer.last
|
32
|
+
n = 0 if n < 0
|
33
|
+
n = last if n > last
|
34
|
+
select n
|
35
|
+
end
|
36
|
+
|
37
|
+
def cursor ()
|
38
|
+
@buffer.pos2cursor pos
|
39
|
+
end
|
40
|
+
|
41
|
+
def cursor= (*args)
|
42
|
+
args.flatten!
|
43
|
+
args << 0 while args.size < 2
|
44
|
+
self.pos = @buffer.cursor2pos *args
|
45
|
+
end
|
46
|
+
|
47
|
+
def row ()
|
48
|
+
@buffer.pos2cursor(pos)[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
def column ()
|
52
|
+
@buffer.pos2cursor(pos)[1]
|
53
|
+
end
|
54
|
+
|
55
|
+
def row= (n)
|
56
|
+
self.cursor = n, column
|
57
|
+
end
|
58
|
+
|
59
|
+
def column= (n)
|
60
|
+
self.cursor = row, n
|
61
|
+
end
|
62
|
+
|
63
|
+
def replace (str, first, last = nil)
|
64
|
+
last = first unless last
|
65
|
+
@buffer.erase first, last
|
66
|
+
@buffer.insert first, str
|
67
|
+
end
|
68
|
+
|
69
|
+
def select (*args)
|
70
|
+
first, last = case args[0]
|
71
|
+
when Range
|
72
|
+
args[0].to_a
|
73
|
+
when Integer
|
74
|
+
args
|
75
|
+
end
|
76
|
+
last = first unless last
|
77
|
+
first, last = last, first unless first < last
|
78
|
+
@first, @last = first, last
|
79
|
+
selection
|
80
|
+
end
|
81
|
+
|
82
|
+
def selection ()
|
83
|
+
@first..@last
|
84
|
+
end
|
85
|
+
|
86
|
+
def selection= (str)
|
87
|
+
select replace(str, @first, @last)
|
88
|
+
end
|
89
|
+
|
90
|
+
def << (str)
|
91
|
+
replace str, last
|
92
|
+
end
|
93
|
+
|
94
|
+
def inspect ()
|
95
|
+
"#<Text row: #{row}, column: #{column}, buffer: #{buffer.inspect}>"
|
96
|
+
end
|
97
|
+
|
98
|
+
end# Text
|
99
|
+
|
100
|
+
|
101
|
+
end# Spacy
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Spacy
|
5
|
+
|
6
|
+
|
7
|
+
class TextBuffer
|
8
|
+
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def initialize (str = nil)
|
12
|
+
@lines = [TextLine.new]
|
13
|
+
insert 0, str.to_s if str
|
14
|
+
end
|
15
|
+
|
16
|
+
def insert (pos, str)
|
17
|
+
last_ = last
|
18
|
+
raise RangeError unless 0 <= pos && pos <= last_
|
19
|
+
str.to_s.split(/(\r\n|\r|\n)/).each do |s|
|
20
|
+
row, col = p2c pos, last_
|
21
|
+
added = 0
|
22
|
+
if s =~ /\r|\n/
|
23
|
+
split_line row, col
|
24
|
+
added = 1
|
25
|
+
else
|
26
|
+
self[row].insert s, col
|
27
|
+
added = s.size
|
28
|
+
end
|
29
|
+
pos += added
|
30
|
+
last_ += added
|
31
|
+
end
|
32
|
+
pos
|
33
|
+
end
|
34
|
+
|
35
|
+
def erase (first, last = nil)
|
36
|
+
last = first + 1 unless last
|
37
|
+
first, last = last, first unless first < last
|
38
|
+
last_ = self.last
|
39
|
+
row1, col1 = p2c first, last_
|
40
|
+
row2, col2 = p2c last, last_
|
41
|
+
return self if row1 == row2 && col1 == col2
|
42
|
+
|
43
|
+
if row1 == row2
|
44
|
+
@lines[row1].erase col1, col2
|
45
|
+
else
|
46
|
+
@lines[row2][0...col2] = @lines[row1][0...col1]
|
47
|
+
@lines[row1...row2] = []
|
48
|
+
end
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def nrow ()
|
53
|
+
@lines.size
|
54
|
+
end
|
55
|
+
|
56
|
+
def ncolumn (row)
|
57
|
+
raise RangeError unless 0 <= row && row < nrow
|
58
|
+
self[row].ncolumn
|
59
|
+
end
|
60
|
+
|
61
|
+
def last ()
|
62
|
+
raise 'Invalid text buffer.' if @lines.empty?
|
63
|
+
inject(0) {|n, line| n + line.ncolumn} - 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def empty? ()
|
67
|
+
nrow == 1 && ncolumn(0) == 1
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_a ()
|
71
|
+
@lines
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s ()
|
75
|
+
to_a.join("\n")
|
76
|
+
end
|
77
|
+
|
78
|
+
def [] (*args)
|
79
|
+
@lines[*args]
|
80
|
+
end
|
81
|
+
|
82
|
+
def []= (row, line)
|
83
|
+
@lines[row] = line.to_textline
|
84
|
+
end
|
85
|
+
|
86
|
+
def each (*args, &block)
|
87
|
+
@lines.each *args, &block
|
88
|
+
end
|
89
|
+
|
90
|
+
def pos2cursor (pos)
|
91
|
+
last_ = last
|
92
|
+
if pos < 0
|
93
|
+
pos = 0
|
94
|
+
elsif pos > last_
|
95
|
+
pos = last_
|
96
|
+
end
|
97
|
+
p2c pos, last_
|
98
|
+
end
|
99
|
+
|
100
|
+
def cursor2pos (row, col)
|
101
|
+
nrow_ = nrow
|
102
|
+
if row < 0
|
103
|
+
row = 0
|
104
|
+
elsif row >= nrow_
|
105
|
+
row = nrow_ - 1
|
106
|
+
end
|
107
|
+
ncol_ = ncolumn(row)
|
108
|
+
if col < 0
|
109
|
+
col = 0
|
110
|
+
elsif col >= ncol_
|
111
|
+
col = ncol_ - 1
|
112
|
+
end
|
113
|
+
c2p row, col, nrow_, ncol_
|
114
|
+
end
|
115
|
+
|
116
|
+
def inspect ()
|
117
|
+
text = @lines.map{|x| x.to_s}.join('\n')[0, 64]
|
118
|
+
"#<TextBuffer #{nrow} lines, '#{text}'>"
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def split_line (row, col)
|
124
|
+
line = self[row]
|
125
|
+
lineend = line.ncolumn - 1
|
126
|
+
newline = TextLine.new line[col...lineend]
|
127
|
+
line[col...lineend] = ''
|
128
|
+
@lines.insert row + 1, newline
|
129
|
+
end
|
130
|
+
|
131
|
+
def p2c (pos, last_)
|
132
|
+
raise RangeError unless 0 <= pos && pos <= last_
|
133
|
+
row = col = n = 0
|
134
|
+
each do |line|
|
135
|
+
nn = n + line.ncolumn
|
136
|
+
if n <= pos && pos < nn
|
137
|
+
col = pos - n
|
138
|
+
break
|
139
|
+
end
|
140
|
+
n = nn
|
141
|
+
row += 1
|
142
|
+
end
|
143
|
+
[row, col]
|
144
|
+
end
|
145
|
+
|
146
|
+
def c2p (row, col, nrow_, ncol_)
|
147
|
+
raise RangeError unless
|
148
|
+
0 <= row && row < nrow_ && 0 <= col && col < ncol_
|
149
|
+
n = 0
|
150
|
+
each.with_index do |line, index|
|
151
|
+
break if index == row
|
152
|
+
n += line.ncolumn
|
153
|
+
end
|
154
|
+
n + col
|
155
|
+
end
|
156
|
+
|
157
|
+
end# TextBuffer
|
158
|
+
|
159
|
+
|
160
|
+
end# Spacy
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
module Spacy
|
5
|
+
|
6
|
+
|
7
|
+
class TextLine
|
8
|
+
|
9
|
+
include Comparable
|
10
|
+
|
11
|
+
def initialize (str = nil)
|
12
|
+
@str = ''
|
13
|
+
insert str, 0 if str
|
14
|
+
end
|
15
|
+
|
16
|
+
def insert (str, pos)
|
17
|
+
raise RangeError unless 0 <= pos && pos <= last
|
18
|
+
str = str.to_s
|
19
|
+
raise ArgumentError, "'str' has new-line char(s)." if str =~ /\r|\n/
|
20
|
+
@str.insert pos, str
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def erase (first, last = nil)
|
25
|
+
last = first + 1 unless last
|
26
|
+
first, last = last, first unless first < last
|
27
|
+
raise RangeError unless 0 <= first && last <= self.last
|
28
|
+
@str[first...last] = '' if first != last
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def concat (str)
|
33
|
+
insert str, last
|
34
|
+
end
|
35
|
+
|
36
|
+
alias << concat
|
37
|
+
|
38
|
+
def last ()
|
39
|
+
@str.size
|
40
|
+
end
|
41
|
+
|
42
|
+
def ncolumn ()
|
43
|
+
last + 1
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s ()
|
47
|
+
@str
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_textline ()
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def [] (*args)
|
55
|
+
@str.[](*args)
|
56
|
+
end
|
57
|
+
|
58
|
+
def []= (*args)
|
59
|
+
@str.[]=(*args)
|
60
|
+
end
|
61
|
+
|
62
|
+
def <=> (obj)
|
63
|
+
to_s <=> obj.to_s
|
64
|
+
end
|
65
|
+
|
66
|
+
def inspect ()
|
67
|
+
"#<TextLine '#{@str}'>"
|
68
|
+
end
|
69
|
+
|
70
|
+
end# TextLine
|
71
|
+
|
72
|
+
|
73
|
+
end# Spacy
|
data/lib/spacy/window.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
require 'rays/image'
|
5
|
+
require 'reflex/application'
|
6
|
+
require 'reflex/window'
|
7
|
+
require 'spacy/text'
|
8
|
+
|
9
|
+
|
10
|
+
module Spacy
|
11
|
+
|
12
|
+
|
13
|
+
class Window < Reflex::Window
|
14
|
+
|
15
|
+
def initialize ()
|
16
|
+
super
|
17
|
+
set :title, Reflex::Application.instance.name
|
18
|
+
set :bounds, 100, 100, 600, 500
|
19
|
+
@text = Text.new
|
20
|
+
p = painter
|
21
|
+
p.background 1
|
22
|
+
p.fill 0
|
23
|
+
p.stroke nil
|
24
|
+
p.font Rays::Font.new "Menlo", 12
|
25
|
+
end
|
26
|
+
|
27
|
+
def update (dt)
|
28
|
+
@t ||= Time.now
|
29
|
+
@c ||= 0
|
30
|
+
redraw
|
31
|
+
@c += 1
|
32
|
+
@fps = @c / (Time.now - @t)
|
33
|
+
puts "#{@fps} FPS" if (@c % 100) == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def draw ()
|
37
|
+
super
|
38
|
+
paint do |p|
|
39
|
+
h = p.font.height
|
40
|
+
draw_text p, h
|
41
|
+
draw_cursor p, h
|
42
|
+
draw_fps p
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def close ()
|
47
|
+
#Profiler__.print_profile STDOUT
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
def key_down (key)
|
52
|
+
@text.selection = key.chars
|
53
|
+
end
|
54
|
+
|
55
|
+
def key_up (key)
|
56
|
+
end
|
57
|
+
|
58
|
+
def points_down (points)
|
59
|
+
end
|
60
|
+
|
61
|
+
def points_up (points)
|
62
|
+
end
|
63
|
+
|
64
|
+
def points_moved (points)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def draw_text (p, lineheight)
|
70
|
+
y = 0
|
71
|
+
@text.each do |line|
|
72
|
+
p.text line, 0, y
|
73
|
+
y += lineheight
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def draw_cursor (p, lineheight)
|
78
|
+
row, col = @text.cursor
|
79
|
+
x = p.font.width @text[row][0..col]
|
80
|
+
p.rect x, row * lineheight, 4, lineheight
|
81
|
+
end
|
82
|
+
|
83
|
+
def draw_fps (p)
|
84
|
+
pos = bounds(0)[1].move_by(-64, -20).to_a(2)
|
85
|
+
p.text "#{@fps.to_i} FPS", *pos if @fps
|
86
|
+
end
|
87
|
+
|
88
|
+
end# Window
|
89
|
+
|
90
|
+
|
91
|
+
end # Spacy
|
data/spacy.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
$: << File.expand_path('../lib', __FILE__)
|
5
|
+
|
6
|
+
require 'spacy/module'
|
7
|
+
|
8
|
+
|
9
|
+
Gem::Specification.new do |s|
|
10
|
+
def glob (*patterns)
|
11
|
+
patterns.map {|pat| Dir.glob(pat).to_a}.flatten
|
12
|
+
end
|
13
|
+
|
14
|
+
mod = Spacy
|
15
|
+
name = mod.name.downcase
|
16
|
+
rdocs = glob *%w[README]
|
17
|
+
|
18
|
+
s.name = name
|
19
|
+
s.summary = 'A text editor written by Ruby.'
|
20
|
+
s.description = 'A text editor runs on Ruby and uses SPACE as a trigger key for every action.'
|
21
|
+
s.version = mod.version
|
22
|
+
|
23
|
+
s.authors = %w[snori]
|
24
|
+
s.email = 'snori@xord.org'
|
25
|
+
s.homepage = "http://github.com/xord/#{name}"
|
26
|
+
|
27
|
+
s.platform = Gem::Platform::RUBY
|
28
|
+
s.required_ruby_version = '>=1.9.0'
|
29
|
+
|
30
|
+
s.add_runtime_dependency 'bundler'
|
31
|
+
s.add_runtime_dependency 'xot'
|
32
|
+
s.add_runtime_dependency 'rays'
|
33
|
+
s.add_runtime_dependency 'reflexion'
|
34
|
+
s.add_development_dependency 'rake'
|
35
|
+
s.add_development_dependency 'gemcutter'
|
36
|
+
|
37
|
+
s.files = `git ls-files`.split $/
|
38
|
+
s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
|
39
|
+
s.test_files = s.files.grep %r{^(test|spec|features)/}
|
40
|
+
s.extra_rdoc_files = rdocs.to_a
|
41
|
+
s.has_rdoc = true
|
42
|
+
|
43
|
+
s.extensions << 'Rakefile'
|
44
|
+
end
|
data/task/mac.rake
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
task :app => 'app:build'
|
5
|
+
|
6
|
+
%w[clean run].each do |t|
|
7
|
+
task t.intern => "app:#{t}"
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
namespace :app do
|
12
|
+
|
13
|
+
|
14
|
+
mod = MODULE
|
15
|
+
name = env :NAME, MODULE.name.downcase
|
16
|
+
bindir = env :BINDIR, 'bin'
|
17
|
+
ruby = env :RUBY, 'ruby'
|
18
|
+
|
19
|
+
bin = "#{bindir}/#{name}"
|
20
|
+
appname = name.capitalize
|
21
|
+
appdir = "#{appname}.app"
|
22
|
+
appbindir = "#{appdir}/Contents/MacOS"
|
23
|
+
out = "#{appbindir}/#{name}"
|
24
|
+
|
25
|
+
tmps = [appdir]
|
26
|
+
|
27
|
+
|
28
|
+
task :build => out
|
29
|
+
|
30
|
+
task :clean do
|
31
|
+
sh %( rm -rf #{tmps.join ' '} )
|
32
|
+
end
|
33
|
+
|
34
|
+
task :run => :app do
|
35
|
+
sh %( #{ruby} #{bin} )
|
36
|
+
end
|
37
|
+
|
38
|
+
file out => [bin, appbindir] do
|
39
|
+
sh %( cp #{bin} #{appbindir} )
|
40
|
+
end
|
41
|
+
|
42
|
+
directory appbindir
|
43
|
+
|
44
|
+
|
45
|
+
end# :app
|
data/task/submodule.rake
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
def env (name, defval = nil)
|
5
|
+
Object.const_get(name) rescue ENV[name.to_s] || defval
|
6
|
+
end unless respond_to? :env
|
7
|
+
|
8
|
+
def header (mod)
|
9
|
+
puts "-- #{mod.to_s.capitalize} " + "-" * 50
|
10
|
+
end unless respond_to? :header
|
11
|
+
|
12
|
+
|
13
|
+
namespace :submodule do
|
14
|
+
|
15
|
+
|
16
|
+
mods = env :SUBMODULES, []
|
17
|
+
git = env :GIT, 'git'
|
18
|
+
|
19
|
+
|
20
|
+
task :init => mods.map {|m| "submodule:#{m}:init"}
|
21
|
+
|
22
|
+
mods.each do |mod|
|
23
|
+
namespace mod.intern do
|
24
|
+
|
25
|
+
rakefile = File.join mod, 'Rakefile'
|
26
|
+
|
27
|
+
task :init => rakefile
|
28
|
+
|
29
|
+
file rakefile do
|
30
|
+
header mod
|
31
|
+
sh %( git submodule update --init #{mod} )
|
32
|
+
sh %( cd #{mod} && git checkout master )
|
33
|
+
end
|
34
|
+
|
35
|
+
end# mod.intern
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end# submodule
|
data/test/helpers.rb
ADDED
data/test/test_text.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
|
6
|
+
require 'helpers'
|
7
|
+
|
8
|
+
|
9
|
+
class TestText < Test::Unit::TestCase
|
10
|
+
|
11
|
+
LINES = %w[123 456]
|
12
|
+
|
13
|
+
def buffer (str = nil)
|
14
|
+
str = LINES.join("\n") unless str
|
15
|
+
str = str.dup if String === str
|
16
|
+
Spacy::TextBuffer.new str
|
17
|
+
end
|
18
|
+
|
19
|
+
def text ()
|
20
|
+
Spacy::Text.new buffer
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_pos ()
|
24
|
+
lineend = LINES[0].size
|
25
|
+
assert_equal [0, 0], text.cursor
|
26
|
+
assert_equal [0, 1], text.tap{|t| t.pos += 1}.cursor
|
27
|
+
assert_equal [0, lineend], text.tap{|t| t.pos = lineend}.cursor
|
28
|
+
assert_equal [1, 0], text.tap{|t| t.pos = lineend + 1}.cursor
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_cursor ()
|
32
|
+
lineend = LINES[0].size
|
33
|
+
size = LINES.inject(0) {|n, s| n + s.size + 1} - 1
|
34
|
+
assert_equal lineend, text.tap{|t| t.cursor = 0, lineend}.pos
|
35
|
+
assert_equal size, text.tap{|t| t.cursor = 1, 4}.pos
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_row ()
|
39
|
+
assert_equal [1, 0], text.tap{|t| t.row += 1}.cursor
|
40
|
+
assert_equal [0, 1], text.tap{|t| t.column += 1}.cursor
|
41
|
+
end
|
42
|
+
|
43
|
+
end# TestText
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
|
6
|
+
require 'helpers'
|
7
|
+
|
8
|
+
|
9
|
+
class TestTextBuffer < Test::Unit::TestCase
|
10
|
+
|
11
|
+
LINES = %w[123 456]
|
12
|
+
|
13
|
+
def buffer (str = nil)
|
14
|
+
str = LINES.join("\n") unless str
|
15
|
+
str = str.dup if String === str
|
16
|
+
Spacy::TextBuffer.new str
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_new ()
|
20
|
+
assert_equal LINES.join("\n"), buffer.to_s
|
21
|
+
assert_equal '123', buffer(123).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_insert ()
|
25
|
+
assert_equal "x123\n456", buffer.tap{|b| b.insert 0, 'x'}.to_s
|
26
|
+
assert_equal "1x23\n456", buffer.tap{|b| b.insert 1, 'x'}.to_s
|
27
|
+
assert_equal "123x\n456", buffer.tap{|b| b.insert 3, 'x'}.to_s
|
28
|
+
assert_equal "123\nx456", buffer.tap{|b| b.insert 4, 'x'}.to_s
|
29
|
+
assert_equal "1a\nb23\n456", buffer.tap{|b| b.insert 1, "a\nb"}.to_s
|
30
|
+
assert_equal "123\n456x", buffer.tap{|b| b.insert b.last, 'x'}.to_s
|
31
|
+
assert_raise(RangeError) {buffer.tap{|b| b.insert -1, 'x'}}
|
32
|
+
assert_raise(RangeError) {buffer.tap{|b| b.insert b.last + 1, 'x'}}
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_erase ()
|
36
|
+
assert_equal "23\n456", buffer.erase(0).to_s
|
37
|
+
assert_equal "123\n456", buffer.erase(0, 0).to_s
|
38
|
+
assert_equal "23\n456", buffer.erase(0, 1).to_s
|
39
|
+
assert_equal "3\n456", buffer.erase(0, 2).to_s
|
40
|
+
assert_equal "\n456", buffer.erase(0, 3).to_s
|
41
|
+
assert_equal "456", buffer.erase(0, 4).to_s
|
42
|
+
assert_equal "56", buffer.erase(0, 5).to_s
|
43
|
+
assert_equal "13\n456", buffer.erase(1, 2).to_s
|
44
|
+
assert_equal "\n456", buffer.erase(3, 0).to_s
|
45
|
+
assert_equal "123\n45", buffer.tap{|b| b.erase b.last - 1}.to_s
|
46
|
+
assert_equal "123\n456", buffer.tap{|b| b.erase b.last, b.last}.to_s
|
47
|
+
assert_raise(RangeError) {buffer.tap{|b| b.erase -1}}
|
48
|
+
assert_raise(RangeError) {buffer.tap{|b| b.erase b.last}}
|
49
|
+
assert_raise(RangeError) {buffer.tap{|b| b.erase -1, 0}}
|
50
|
+
assert_raise(RangeError) {buffer.tap{|b| b.erase 0, b.last + 1}}
|
51
|
+
assert_raise(RangeError) {buffer.tap{|b| b.erase -1, b.last + 1}}
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_nrow ()
|
55
|
+
assert_equal LINES.size, buffer.nrow
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_ncolumn ()
|
59
|
+
assert_equal LINES[0].size + 1, buffer.ncolumn(0)
|
60
|
+
assert_equal LINES[1].size + 1, buffer.ncolumn(1)
|
61
|
+
assert_raise(RangeError) {buffer.ncolumn(-1)}
|
62
|
+
assert_raise(RangeError) {buffer.ncolumn(2)}
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_last ()
|
66
|
+
assert_equal LINES.join("\n").size, buffer.last
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_to_a ()
|
70
|
+
assert_equal LINES.map{|s| Spacy::TextLine.new s}, buffer.to_a
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_to_s ()
|
74
|
+
assert_equal LINES.join("\n"), buffer.to_s
|
75
|
+
assert_equal '', buffer('').to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_each ()
|
79
|
+
buffer.each.with_index do |line, index|
|
80
|
+
assert_equal LINES[index], line.to_s
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end# TestTextBuffer
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
|
6
|
+
require 'helpers'
|
7
|
+
|
8
|
+
|
9
|
+
class TestTextLine < Test::Unit::TestCase
|
10
|
+
|
11
|
+
LINE = '123'
|
12
|
+
|
13
|
+
def line (str = nil)
|
14
|
+
str = LINE unless str
|
15
|
+
str = str.dup if String === str
|
16
|
+
Spacy::TextLine.new str
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_new ()
|
20
|
+
assert_equal '123', line.to_s
|
21
|
+
assert_equal '123', line(123).to_s
|
22
|
+
assert_raise(ArgumentError) {line "123\n"}
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_insert ()
|
26
|
+
assert_equal 'x123', line.insert('x', 0).to_s
|
27
|
+
assert_equal '1x23', line.insert('x', 1).to_s
|
28
|
+
assert_equal '123x', line.tap{|l| l.insert 'x', l.last}.to_s
|
29
|
+
assert_raise(RangeError) {line.insert 'x', -1}
|
30
|
+
assert_raise(RangeError) {line.tap{|l| l.insert 'x', l.last + 1}}
|
31
|
+
assert_raise(ArgumentError) {line.insert "x\n", 0}
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_erase ()
|
35
|
+
assert_equal '23', line.erase(0).to_s
|
36
|
+
assert_equal '123', line.erase(0, 0).to_s
|
37
|
+
assert_equal '23', line.erase(0, 1).to_s
|
38
|
+
assert_equal '13', line.erase(1, 2).to_s
|
39
|
+
assert_equal '', line.tap{|l| l.erase 0, l.last}.to_s
|
40
|
+
assert_equal '1', line.tap{|l| l.erase 1, l.last}.to_s
|
41
|
+
assert_equal '', line.tap{|l| l.erase l.last, 0}.to_s
|
42
|
+
assert_raise(RangeError) {line.erase -1, 0}
|
43
|
+
assert_raise(RangeError) {line.tap{|l| l.erase 0, l.last + 1}}
|
44
|
+
assert_raise(RangeError) {line.tap{|l| l.erase -1, l.last + 1}}
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_ncolumn ()
|
48
|
+
assert_equal LINE.size + 1, line.ncolumn
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_to_s ()
|
52
|
+
assert_equal '123', line.to_s
|
53
|
+
assert_equal '', line('').to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
end# TestTextLine
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spacy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.4
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- snori
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: xot
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rays
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: reflexion
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: gemcutter
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: A text editor runs on Ruby and uses SPACE as a trigger key for every
|
111
|
+
action.
|
112
|
+
email: snori@xord.org
|
113
|
+
executables:
|
114
|
+
- spacy
|
115
|
+
extensions:
|
116
|
+
- Rakefile
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- .gitmodules
|
121
|
+
- ChangeLog
|
122
|
+
- Gemfile
|
123
|
+
- Rakefile
|
124
|
+
- VERSION
|
125
|
+
- bin/spacy
|
126
|
+
- lib/spacy.rb
|
127
|
+
- lib/spacy/application.rb
|
128
|
+
- lib/spacy/extensions.rb
|
129
|
+
- lib/spacy/key.rb
|
130
|
+
- lib/spacy/keymap.rb
|
131
|
+
- lib/spacy/keystroke.rb
|
132
|
+
- lib/spacy/module.rb
|
133
|
+
- lib/spacy/text.rb
|
134
|
+
- lib/spacy/textbuffer.rb
|
135
|
+
- lib/spacy/textline.rb
|
136
|
+
- lib/spacy/window.rb
|
137
|
+
- spacy.gemspec
|
138
|
+
- task/mac.rake
|
139
|
+
- task/submodule.rake
|
140
|
+
- test/helpers.rb
|
141
|
+
- test/test_text.rb
|
142
|
+
- test/test_textbuffer.rb
|
143
|
+
- test/test_textline.rb
|
144
|
+
homepage: http://github.com/xord/spacy
|
145
|
+
licenses: []
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
152
|
+
requirements:
|
153
|
+
- - ! '>='
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: 1.9.0
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ! '>='
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
segments:
|
163
|
+
- 0
|
164
|
+
hash: 2855528895130620030
|
165
|
+
requirements: []
|
166
|
+
rubyforge_project:
|
167
|
+
rubygems_version: 1.8.25
|
168
|
+
signing_key:
|
169
|
+
specification_version: 3
|
170
|
+
summary: A text editor written by Ruby.
|
171
|
+
test_files:
|
172
|
+
- test/helpers.rb
|
173
|
+
- test/test_text.rb
|
174
|
+
- test/test_textbuffer.rb
|
175
|
+
- test/test_textline.rb
|