spacy 0.1.4
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/.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
|