vim-flavor 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +44 -0
- data/lib/vim-flavor.rb +11 -462
- data/lib/vim-flavor/cli.rb +29 -0
- data/lib/vim-flavor/facade.rb +156 -0
- data/lib/vim-flavor/flavor.rb +119 -0
- data/lib/vim-flavor/flavorfile.rb +62 -0
- data/lib/vim-flavor/lockfile.rb +64 -0
- data/lib/vim-flavor/stringextension.rb +9 -0
- data/lib/vim-flavor/version.rb +1 -1
- data/lib/vim-flavor/versionconstraint.rb +48 -0
- data/spec/facade_spec.rb +1 -1
- data/spec/flavor_spec.rb +6 -6
- metadata +9 -2
data/README.md
CHANGED
@@ -28,6 +28,50 @@
|
|
28
28
|
gem install vim-flavor
|
29
29
|
|
30
30
|
|
31
|
+
### Installable plugins
|
32
|
+
|
33
|
+
Not all Vim plugins can be installed with vim-flavor.
|
34
|
+
vim-flavor can install plugins which meet the following conditions:
|
35
|
+
|
36
|
+
* Plugins must have dedicated Git repositories.
|
37
|
+
vim-flavor does not support other version control systems.
|
38
|
+
This is an intentional design. Because:
|
39
|
+
* [vim-scripts.org](http://vim-scripts.org/) provides
|
40
|
+
[a comprehensive Git mirrors](https://github.com/vim-scripts) for
|
41
|
+
[plugins uploaded to www.vim.org](http://www.vim.org/scripts/index.php).
|
42
|
+
* Experimental plugins which are not uploaded to www.vim.org
|
43
|
+
are usually found in [GitHub](https://github.com/).
|
44
|
+
* Plugins must follow [the versioning pocilies of
|
45
|
+
RubyGems](http://docs.rubygems.org/read/chapter/7#page26) and have "version"
|
46
|
+
tags in their repositories. For example, if there is the version 1.2.3 of
|
47
|
+
a plugin, its repository must have the tag `1.2.3`, and the files of the
|
48
|
+
version 1.2.3 can be checked out via the tag `1.2.3`. In other words,
|
49
|
+
plugins which do not have proper tags are not installabe.
|
50
|
+
This is an intentional design. Because:
|
51
|
+
* It's not possible to determine whether two versions are compatible or not
|
52
|
+
without "version" tags. Compatibility is a big problem to resolve
|
53
|
+
dependencies of plugins. For example, if plugin A requires plugin X 1.2.3
|
54
|
+
or later while plugin B requires plugin X 2.0 or later, it's not possible
|
55
|
+
to use A and B at the same time. Such problems should be detected before
|
56
|
+
installing plugins.
|
57
|
+
* Git mirrors by vim-scripts.org are tagged with version numbers.
|
58
|
+
* Some Git repositories might not have "version" tags.
|
59
|
+
Such plugins are not ready to use for everyone.
|
60
|
+
So that it should not be installable.
|
61
|
+
* Plugins must have proper directory structures.
|
62
|
+
For example, directories such as `autoload`, `syntax` etc should exist in
|
63
|
+
the roots of plugins.
|
64
|
+
This is an intentional design. Because:
|
65
|
+
* Git mirrors by vim-scripts.org have proper directory structures even if
|
66
|
+
the original plugins are uploaded to www.vim.org without proper directory
|
67
|
+
structures. (A good example is
|
68
|
+
[a.vim](http://www.vim.org/scripts/script.php?script_id=31) and
|
69
|
+
[its mirror](https://github.com/vim-scripts/a.vim).)
|
70
|
+
* Other Git repositoris might not have proper directory structures.
|
71
|
+
Such plugins are not ready to use for everyone.
|
72
|
+
So that it should not be installable.
|
73
|
+
|
74
|
+
|
31
75
|
|
32
76
|
|
33
77
|
## Typical usage
|
data/lib/vim-flavor.rb
CHANGED
@@ -1,66 +1,24 @@
|
|
1
1
|
require 'bundler/setup'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'thor'
|
4
|
-
require 'vim-flavor/version'
|
5
|
-
require 'yaml'
|
6
2
|
|
7
3
|
module Vim
|
8
4
|
module Flavor
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
[
|
6
|
+
:CLI,
|
7
|
+
:Facade,
|
8
|
+
:Flavor,
|
9
|
+
:FlavorFile,
|
10
|
+
:LockFile,
|
11
|
+
:StringExtension,
|
12
|
+
:VERSION,
|
13
|
+
:VersionConstraint,
|
14
|
+
].each do |name|
|
15
|
+
autoload name, "vim-flavor/#{name.to_s().downcase()}"
|
13
16
|
end
|
14
17
|
|
15
18
|
class ::String
|
16
19
|
include StringExtension
|
17
20
|
end
|
18
21
|
|
19
|
-
class VersionConstraint
|
20
|
-
attr_reader :base_version, :operator
|
21
|
-
|
22
|
-
def initialize(s)
|
23
|
-
@base_version, @operator = parse(s)
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_s()
|
27
|
-
"#{@operator} #{@base_version}"
|
28
|
-
end
|
29
|
-
|
30
|
-
def ==(other)
|
31
|
-
self.base_version == other.base_version &&
|
32
|
-
self.operator == other.operator
|
33
|
-
end
|
34
|
-
|
35
|
-
def parse(s)
|
36
|
-
m = /^\s*(>=|~>)\s+(\S+)$/.match(s)
|
37
|
-
if m then
|
38
|
-
[Gem::Version.create(m[2]), m[1]]
|
39
|
-
else
|
40
|
-
raise "Invalid version constraint: #{s.inspect}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def compatible?(other_version_or_s)
|
45
|
-
v = Gem::Version.create(other_version_or_s)
|
46
|
-
if @operator == '~>' then
|
47
|
-
self.base_version.bump() > v and v >= self.base_version
|
48
|
-
elsif @operator == '>=' then
|
49
|
-
v >= self.base_version
|
50
|
-
else
|
51
|
-
raise NotImplementedError
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def find_the_best_version(versions)
|
56
|
-
versions.
|
57
|
-
select {|v| compatible?(v)}.
|
58
|
-
sort().
|
59
|
-
reverse().
|
60
|
-
first
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
22
|
class << self
|
65
23
|
@@dot_path = File.expand_path('~/.vim-flavor')
|
66
24
|
|
@@ -72,414 +30,5 @@ module Vim
|
|
72
30
|
@@dot_path = path
|
73
31
|
end
|
74
32
|
end
|
75
|
-
|
76
|
-
class Flavor
|
77
|
-
@@properties = [
|
78
|
-
:groups,
|
79
|
-
:locked_version,
|
80
|
-
:repo_name,
|
81
|
-
:repo_uri,
|
82
|
-
:version_contraint,
|
83
|
-
]
|
84
|
-
|
85
|
-
@@properties.each do |p|
|
86
|
-
attr_accessor p
|
87
|
-
end
|
88
|
-
|
89
|
-
def initialize()
|
90
|
-
@groups = []
|
91
|
-
end
|
92
|
-
|
93
|
-
def ==(other)
|
94
|
-
return false if self.class != other.class
|
95
|
-
@@properties.all? do |p|
|
96
|
-
self.send(p) == other.send(p)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def zapped_repo_dir_name
|
101
|
-
@repo_name.gsub(/[^A-Za-z0-9._-]/, '_')
|
102
|
-
end
|
103
|
-
|
104
|
-
def cached_repo_path
|
105
|
-
@cached_repo_path ||=
|
106
|
-
"#{Vim::Flavor.dot_path}/repos/#{zapped_repo_dir_name}"
|
107
|
-
end
|
108
|
-
|
109
|
-
def make_deploy_path(vimfiles_path)
|
110
|
-
"#{vimfiles_path.to_flavors_path()}/#{zapped_repo_dir_name}"
|
111
|
-
end
|
112
|
-
|
113
|
-
def clone()
|
114
|
-
message = %x[
|
115
|
-
{
|
116
|
-
git clone '#{@repo_uri}' '#{cached_repo_path}'
|
117
|
-
} 2>&1
|
118
|
-
]
|
119
|
-
if $? != 0 then
|
120
|
-
raise RuntimeError, message
|
121
|
-
end
|
122
|
-
true
|
123
|
-
end
|
124
|
-
|
125
|
-
def fetch()
|
126
|
-
message = %x[
|
127
|
-
{
|
128
|
-
cd #{cached_repo_path.inspect} &&
|
129
|
-
git fetch origin
|
130
|
-
} 2>&1
|
131
|
-
]
|
132
|
-
if $? != 0 then
|
133
|
-
raise RuntimeError, message
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def deploy(vimfiles_path)
|
138
|
-
deploy_path = make_deploy_path(vimfiles_path)
|
139
|
-
message = %x[
|
140
|
-
{
|
141
|
-
cd '#{cached_repo_path}' &&
|
142
|
-
git checkout -f #{locked_version.inspect} &&
|
143
|
-
git checkout-index -a -f --prefix='#{deploy_path}/' &&
|
144
|
-
{
|
145
|
-
vim -u NONE -i NONE -n -N -e -s -c '
|
146
|
-
silent! helptags #{deploy_path}/doc
|
147
|
-
qall!
|
148
|
-
' || true
|
149
|
-
}
|
150
|
-
} 2>&1
|
151
|
-
]
|
152
|
-
if $? != 0 then
|
153
|
-
raise RuntimeError, message
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def undeploy(vimfiles_path)
|
158
|
-
deploy_path = make_deploy_path(vimfiles_path)
|
159
|
-
message = %x[
|
160
|
-
{
|
161
|
-
rm -fr '#{deploy_path}'
|
162
|
-
} 2>&1
|
163
|
-
]
|
164
|
-
if $? != 0 then
|
165
|
-
raise RuntimeError, message
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def list_versions()
|
170
|
-
tags = %x[
|
171
|
-
{
|
172
|
-
cd '#{cached_repo_path}' &&
|
173
|
-
git tag
|
174
|
-
} 2>&1
|
175
|
-
]
|
176
|
-
if $? != 0 then
|
177
|
-
raise RuntimeError, message
|
178
|
-
end
|
179
|
-
|
180
|
-
tags.
|
181
|
-
split(/[\r\n]/).
|
182
|
-
select {|t| t != ''}.
|
183
|
-
map {|t| Gem::Version.create(t)}
|
184
|
-
end
|
185
|
-
|
186
|
-
def update_locked_version()
|
187
|
-
@locked_version =
|
188
|
-
version_contraint.find_the_best_version(list_versions())
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
class FlavorFile
|
193
|
-
attr_reader :flavors
|
194
|
-
|
195
|
-
def initialize()
|
196
|
-
@flavors = {}
|
197
|
-
@default_groups = [:default]
|
198
|
-
end
|
199
|
-
|
200
|
-
def interpret(&block)
|
201
|
-
instance_eval(&block)
|
202
|
-
end
|
203
|
-
|
204
|
-
def eval_flavorfile(flavorfile_path)
|
205
|
-
content = File.open(flavorfile_path, 'rb') do |f|
|
206
|
-
f.read()
|
207
|
-
end
|
208
|
-
interpret do
|
209
|
-
instance_eval(content)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def repo_uri_from_repo_name(repo_name)
|
214
|
-
if /^([^\/]+)$/.match(repo_name) then
|
215
|
-
m = Regexp.last_match
|
216
|
-
"git://github.com/vim-scripts/#{m[1]}.git"
|
217
|
-
elsif /^([A-Za-z0-9_-]+)\/(.*)$/.match(repo_name) then
|
218
|
-
m = Regexp.last_match
|
219
|
-
"git://github.com/#{m[1]}/#{m[2]}.git"
|
220
|
-
elsif /^[a-z]+:\/\/.*$/.match(repo_name) then
|
221
|
-
repo_name
|
222
|
-
else
|
223
|
-
raise "repo_name is written in invalid format: #{repo_name.inspect}"
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def flavor(repo_name, *args)
|
228
|
-
options = Hash === args.last ? args.pop : {}
|
229
|
-
options[:groups] ||= []
|
230
|
-
version_contraint = VersionConstraint.new(args.last || '>= 0')
|
231
|
-
|
232
|
-
f = Flavor.new()
|
233
|
-
f.repo_name = repo_name
|
234
|
-
f.repo_uri = repo_uri_from_repo_name(repo_name)
|
235
|
-
f.version_contraint = version_contraint
|
236
|
-
f.groups = @default_groups + options[:groups]
|
237
|
-
|
238
|
-
@flavors[f.repo_uri] = f
|
239
|
-
end
|
240
|
-
|
241
|
-
def group(*group_names, &block)
|
242
|
-
@default_groups.concat(group_names)
|
243
|
-
yield
|
244
|
-
ensure
|
245
|
-
group_names.each do
|
246
|
-
@default_groups.pop()
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
class LockFile
|
252
|
-
# TODO: Resolve dependencies recursively.
|
253
|
-
|
254
|
-
attr_reader :flavors, :path
|
255
|
-
|
256
|
-
def initialize(path)
|
257
|
-
@flavors = {} # repo_uri => flavor
|
258
|
-
@path = path
|
259
|
-
end
|
260
|
-
|
261
|
-
def load()
|
262
|
-
h = File.open(@path, 'rb') do |f|
|
263
|
-
YAML.load(f.read())
|
264
|
-
end
|
265
|
-
|
266
|
-
@flavors = self.class.flavors_from_poro(h[:flavors])
|
267
|
-
end
|
268
|
-
|
269
|
-
def save()
|
270
|
-
h = {}
|
271
|
-
|
272
|
-
h[:flavors] = self.class.poro_from_flavors(@flavors)
|
273
|
-
|
274
|
-
File.open(@path, 'wb') do |f|
|
275
|
-
YAML.dump(h, f)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
def self.poro_from_flavors(flavors)
|
280
|
-
Hash[
|
281
|
-
flavors.values.map {|f|
|
282
|
-
[
|
283
|
-
f.repo_uri,
|
284
|
-
{
|
285
|
-
:groups => f.groups,
|
286
|
-
:locked_version => f.locked_version.to_s(),
|
287
|
-
:repo_name => f.repo_name,
|
288
|
-
:version_contraint => f.version_contraint.to_s(),
|
289
|
-
}
|
290
|
-
]
|
291
|
-
}
|
292
|
-
]
|
293
|
-
end
|
294
|
-
|
295
|
-
def self.flavors_from_poro(poro)
|
296
|
-
Hash[
|
297
|
-
poro.to_a().map {|repo_uri, h|
|
298
|
-
f = Flavor.new()
|
299
|
-
f.groups = h[:groups]
|
300
|
-
f.locked_version = Gem::Version.create(h[:locked_version])
|
301
|
-
f.repo_name = h[:repo_name]
|
302
|
-
f.repo_uri = repo_uri
|
303
|
-
f.version_contraint = VersionConstraint.new(h[:version_contraint])
|
304
|
-
[f.repo_uri, f]
|
305
|
-
}
|
306
|
-
]
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
class Facade
|
311
|
-
attr_reader :flavorfile
|
312
|
-
attr_accessor :flavorfile_path
|
313
|
-
attr_reader :lockfile
|
314
|
-
attr_accessor :lockfile_path
|
315
|
-
attr_accessor :traced
|
316
|
-
|
317
|
-
def initialize()
|
318
|
-
@flavorfile = nil # FlavorFile
|
319
|
-
@flavorfile_path = "#{Dir.getwd()}/VimFlavor"
|
320
|
-
@lockfile = nil # LockFile
|
321
|
-
@lockfile_path = "#{Dir.getwd()}/VimFlavor.lock"
|
322
|
-
@traced = false
|
323
|
-
end
|
324
|
-
|
325
|
-
def trace(message)
|
326
|
-
print(message) if @traced
|
327
|
-
end
|
328
|
-
|
329
|
-
def load()
|
330
|
-
@flavorfile = FlavorFile.new()
|
331
|
-
@flavorfile.eval_flavorfile(@flavorfile_path)
|
332
|
-
|
333
|
-
@lockfile = LockFile.new(@lockfile_path)
|
334
|
-
@lockfile.load() if File.exists?(@lockfile_path)
|
335
|
-
end
|
336
|
-
|
337
|
-
def make_new_flavors(current_flavors, locked_flavors, mode)
|
338
|
-
new_flavors = {}
|
339
|
-
|
340
|
-
current_flavors.each do |repo_uri, cf|
|
341
|
-
lf = locked_flavors[repo_uri]
|
342
|
-
nf = cf.dup()
|
343
|
-
|
344
|
-
nf.locked_version =
|
345
|
-
if (not lf) or
|
346
|
-
cf.version_contraint != lf.version_contraint or
|
347
|
-
mode == :update then
|
348
|
-
cf.locked_version
|
349
|
-
else
|
350
|
-
lf.locked_version
|
351
|
-
end
|
352
|
-
|
353
|
-
new_flavors[repo_uri] = nf
|
354
|
-
end
|
355
|
-
|
356
|
-
new_flavors
|
357
|
-
end
|
358
|
-
|
359
|
-
def create_vim_script_for_bootstrap(vimfiles_path)
|
360
|
-
bootstrap_path = "#{vimfiles_path.to_flavors_path()}/bootstrap.vim"
|
361
|
-
FileUtils.mkdir_p(File.dirname(bootstrap_path))
|
362
|
-
File.open(bootstrap_path, 'w') do |f|
|
363
|
-
f.write(<<-'END')
|
364
|
-
function! s:bootstrap()
|
365
|
-
let current_rtp = &runtimepath
|
366
|
-
let current_rtps = split(current_rtp, ',')
|
367
|
-
set runtimepath&
|
368
|
-
let default_rtp = &runtimepath
|
369
|
-
let default_rtps = split(default_rtp, ',')
|
370
|
-
let user_dir = default_rtps[0]
|
371
|
-
let user_after_dir = default_rtps[-1]
|
372
|
-
let base_rtps =
|
373
|
-
\ filter(copy(current_rtps),
|
374
|
-
\ 'v:val !=# user_dir && v:val !=# user_after_dir')
|
375
|
-
let flavor_dirs =
|
376
|
-
\ filter(split(glob(user_dir . '/flavors/*'), '\n'),
|
377
|
-
\ 'isdirectory(v:val)')
|
378
|
-
let new_rtps =
|
379
|
-
\ []
|
380
|
-
\ + [user_dir]
|
381
|
-
\ + flavor_dirs
|
382
|
-
\ + base_rtps
|
383
|
-
\ + map(reverse(copy(flavor_dirs)), 'v:val . "/after"')
|
384
|
-
\ + [user_after_dir]
|
385
|
-
let &runtimepath = join(new_rtps, ',')
|
386
|
-
endfunction
|
387
|
-
|
388
|
-
call s:bootstrap()
|
389
|
-
END
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
def deploy_flavors(flavor_list, vimfiles_path)
|
394
|
-
FileUtils.rm_rf(
|
395
|
-
["#{vimfiles_path.to_flavors_path()}"],
|
396
|
-
:secure => true
|
397
|
-
)
|
398
|
-
|
399
|
-
create_vim_script_for_bootstrap(vimfiles_path)
|
400
|
-
flavor_list.each do |f|
|
401
|
-
trace("Deploying #{f.repo_name} (#{f.locked_version})\n")
|
402
|
-
f.deploy(vimfiles_path)
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
def save_lockfile()
|
407
|
-
@lockfile.save()
|
408
|
-
end
|
409
|
-
|
410
|
-
def complete_locked_flavors(mode)
|
411
|
-
nfs = {}
|
412
|
-
@flavorfile.flavors.each do |repo_uri, cf|
|
413
|
-
nf = cf.dup()
|
414
|
-
lf = @lockfile.flavors[repo_uri]
|
415
|
-
|
416
|
-
trace("Using #{nf.repo_name} ... ")
|
417
|
-
begin
|
418
|
-
if not File.exists?(nf.cached_repo_path)
|
419
|
-
nf.clone()
|
420
|
-
end
|
421
|
-
|
422
|
-
if mode == :upgrade_all or
|
423
|
-
(not lf) or
|
424
|
-
nf.version_contraint != lf.version_contraint then
|
425
|
-
nf.fetch()
|
426
|
-
nf.update_locked_version()
|
427
|
-
else
|
428
|
-
nf.locked_version = lf.locked_version
|
429
|
-
end
|
430
|
-
end
|
431
|
-
trace("(#{nf.locked_version})\n")
|
432
|
-
|
433
|
-
nfs[repo_uri] = nf
|
434
|
-
end
|
435
|
-
|
436
|
-
@lockfile.instance_eval do
|
437
|
-
@flavors = nfs
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
def get_default_vimfiles_path()
|
442
|
-
# FIXME: Compute more appropriate value.
|
443
|
-
"#{ENV['HOME']}/.vim"
|
444
|
-
end
|
445
|
-
|
446
|
-
def install(vimfiles_path)
|
447
|
-
load()
|
448
|
-
complete_locked_flavors(:upgrade_if_necessary)
|
449
|
-
save_lockfile()
|
450
|
-
deploy_flavors(lockfile.flavors.values, vimfiles_path)
|
451
|
-
end
|
452
|
-
|
453
|
-
def upgrade(vimfiles_path)
|
454
|
-
load()
|
455
|
-
complete_locked_flavors(:upgrade_all)
|
456
|
-
save_lockfile()
|
457
|
-
deploy_flavors(lockfile.flavors.values, vimfiles_path)
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
class CLI < Thor
|
462
|
-
desc 'install', 'Install Vim plugins according to VimFlavor file.'
|
463
|
-
method_option :vimfiles_path,
|
464
|
-
:desc => 'A path to your vimfiles directory.'
|
465
|
-
def install()
|
466
|
-
facade = Facade.new()
|
467
|
-
facade.traced = true
|
468
|
-
facade.install(
|
469
|
-
options[:vimfiles_path] || facade.get_default_vimfiles_path()
|
470
|
-
)
|
471
|
-
end
|
472
|
-
|
473
|
-
desc 'upgrade', 'Upgrade Vim plugins according to VimFlavor file.'
|
474
|
-
method_option :vimfiles_path,
|
475
|
-
:desc => 'A path to your vimfiles directory.'
|
476
|
-
def upgrade()
|
477
|
-
facade = Facade.new()
|
478
|
-
facade.traced = true
|
479
|
-
facade.upgrade(
|
480
|
-
options[:vimfiles_path] || facade.get_default_vimfiles_path()
|
481
|
-
)
|
482
|
-
end
|
483
|
-
end
|
484
33
|
end
|
485
34
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Vim
|
4
|
+
module Flavor
|
5
|
+
class CLI < Thor
|
6
|
+
desc 'install', 'Install Vim plugins according to VimFlavor file.'
|
7
|
+
method_option :vimfiles_path,
|
8
|
+
:desc => 'A path to your vimfiles directory.'
|
9
|
+
def install()
|
10
|
+
facade = Facade.new()
|
11
|
+
facade.traced = true
|
12
|
+
facade.install(
|
13
|
+
options[:vimfiles_path] || facade.get_default_vimfiles_path()
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'upgrade', 'Upgrade Vim plugins according to VimFlavor file.'
|
18
|
+
method_option :vimfiles_path,
|
19
|
+
:desc => 'A path to your vimfiles directory.'
|
20
|
+
def upgrade()
|
21
|
+
facade = Facade.new()
|
22
|
+
facade.traced = true
|
23
|
+
facade.upgrade(
|
24
|
+
options[:vimfiles_path] || facade.get_default_vimfiles_path()
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Vim
|
4
|
+
module Flavor
|
5
|
+
class Facade
|
6
|
+
attr_reader :flavorfile
|
7
|
+
attr_accessor :flavorfile_path
|
8
|
+
attr_reader :lockfile
|
9
|
+
attr_accessor :lockfile_path
|
10
|
+
attr_accessor :traced
|
11
|
+
|
12
|
+
def initialize()
|
13
|
+
@flavorfile = nil # FlavorFile
|
14
|
+
@flavorfile_path = "#{Dir.getwd()}/VimFlavor"
|
15
|
+
@lockfile = nil # LockFile
|
16
|
+
@lockfile_path = "#{Dir.getwd()}/VimFlavor.lock"
|
17
|
+
@traced = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def trace(message)
|
21
|
+
print(message) if @traced
|
22
|
+
end
|
23
|
+
|
24
|
+
def load()
|
25
|
+
@flavorfile = FlavorFile.new()
|
26
|
+
@flavorfile.eval_flavorfile(@flavorfile_path)
|
27
|
+
|
28
|
+
@lockfile = LockFile.new(@lockfile_path)
|
29
|
+
@lockfile.load() if File.exists?(@lockfile_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def make_new_flavors(current_flavors, locked_flavors, mode)
|
33
|
+
new_flavors = {}
|
34
|
+
|
35
|
+
current_flavors.each do |repo_uri, cf|
|
36
|
+
lf = locked_flavors[repo_uri]
|
37
|
+
nf = cf.dup()
|
38
|
+
|
39
|
+
nf.locked_version =
|
40
|
+
if (not lf) or
|
41
|
+
cf.version_contraint != lf.version_contraint or
|
42
|
+
mode == :update then
|
43
|
+
cf.locked_version
|
44
|
+
else
|
45
|
+
lf.locked_version
|
46
|
+
end
|
47
|
+
|
48
|
+
new_flavors[repo_uri] = nf
|
49
|
+
end
|
50
|
+
|
51
|
+
new_flavors
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_vim_script_for_bootstrap(vimfiles_path)
|
55
|
+
bootstrap_path = "#{vimfiles_path.to_flavors_path()}/bootstrap.vim"
|
56
|
+
FileUtils.mkdir_p(File.dirname(bootstrap_path))
|
57
|
+
File.open(bootstrap_path, 'w') do |f|
|
58
|
+
f.write(<<-'END')
|
59
|
+
function! s:bootstrap()
|
60
|
+
let current_rtp = &runtimepath
|
61
|
+
let current_rtps = split(current_rtp, ',')
|
62
|
+
set runtimepath&
|
63
|
+
let default_rtp = &runtimepath
|
64
|
+
let default_rtps = split(default_rtp, ',')
|
65
|
+
let user_dir = default_rtps[0]
|
66
|
+
let user_after_dir = default_rtps[-1]
|
67
|
+
let base_rtps =
|
68
|
+
\ filter(copy(current_rtps),
|
69
|
+
\ 'v:val !=# user_dir && v:val !=# user_after_dir')
|
70
|
+
let flavor_dirs =
|
71
|
+
\ filter(split(glob(user_dir . '/flavors/*'), '\n'),
|
72
|
+
\ 'isdirectory(v:val)')
|
73
|
+
let new_rtps =
|
74
|
+
\ []
|
75
|
+
\ + [user_dir]
|
76
|
+
\ + flavor_dirs
|
77
|
+
\ + base_rtps
|
78
|
+
\ + map(reverse(copy(flavor_dirs)), 'v:val . "/after"')
|
79
|
+
\ + [user_after_dir]
|
80
|
+
let &runtimepath = join(new_rtps, ',')
|
81
|
+
endfunction
|
82
|
+
|
83
|
+
call s:bootstrap()
|
84
|
+
END
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def deploy_flavors(flavor_list, vimfiles_path)
|
89
|
+
FileUtils.rm_rf(
|
90
|
+
["#{vimfiles_path.to_flavors_path()}"],
|
91
|
+
:secure => true
|
92
|
+
)
|
93
|
+
|
94
|
+
create_vim_script_for_bootstrap(vimfiles_path)
|
95
|
+
flavor_list.each do |f|
|
96
|
+
trace("Deploying #{f.repo_name} (#{f.locked_version})\n")
|
97
|
+
f.deploy(vimfiles_path)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def save_lockfile()
|
102
|
+
@lockfile.save()
|
103
|
+
end
|
104
|
+
|
105
|
+
def complete_locked_flavors(mode)
|
106
|
+
nfs = {}
|
107
|
+
@flavorfile.flavors.each do |repo_uri, cf|
|
108
|
+
nf = cf.dup()
|
109
|
+
lf = @lockfile.flavors[repo_uri]
|
110
|
+
|
111
|
+
trace("Using #{nf.repo_name} ... ")
|
112
|
+
begin
|
113
|
+
if not File.exists?(nf.cached_repo_path)
|
114
|
+
nf.clone()
|
115
|
+
end
|
116
|
+
|
117
|
+
if mode == :upgrade_all or
|
118
|
+
(not lf) or
|
119
|
+
nf.version_contraint != lf.version_contraint then
|
120
|
+
nf.fetch()
|
121
|
+
nf.update_locked_version()
|
122
|
+
else
|
123
|
+
nf.locked_version = lf.locked_version
|
124
|
+
end
|
125
|
+
end
|
126
|
+
trace("(#{nf.locked_version})\n")
|
127
|
+
|
128
|
+
nfs[repo_uri] = nf
|
129
|
+
end
|
130
|
+
|
131
|
+
@lockfile.instance_eval do
|
132
|
+
@flavors = nfs
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def get_default_vimfiles_path()
|
137
|
+
# FIXME: Compute more appropriate value.
|
138
|
+
"#{ENV['HOME']}/.vim"
|
139
|
+
end
|
140
|
+
|
141
|
+
def install(vimfiles_path)
|
142
|
+
load()
|
143
|
+
complete_locked_flavors(:upgrade_if_necessary)
|
144
|
+
save_lockfile()
|
145
|
+
deploy_flavors(lockfile.flavors.values, vimfiles_path)
|
146
|
+
end
|
147
|
+
|
148
|
+
def upgrade(vimfiles_path)
|
149
|
+
load()
|
150
|
+
complete_locked_flavors(:upgrade_all)
|
151
|
+
save_lockfile()
|
152
|
+
deploy_flavors(lockfile.flavors.values, vimfiles_path)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Vim
|
2
|
+
module Flavor
|
3
|
+
class Flavor
|
4
|
+
@@properties = [
|
5
|
+
:groups,
|
6
|
+
:locked_version,
|
7
|
+
:repo_name,
|
8
|
+
:repo_uri,
|
9
|
+
:version_contraint,
|
10
|
+
]
|
11
|
+
|
12
|
+
@@properties.each do |p|
|
13
|
+
attr_accessor p
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
@groups = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
return false if self.class != other.class
|
22
|
+
@@properties.all? do |p|
|
23
|
+
self.send(p) == other.send(p)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def zapped_repo_dir_name
|
28
|
+
@repo_name.gsub(/[^A-Za-z0-9._-]/, '_')
|
29
|
+
end
|
30
|
+
|
31
|
+
def cached_repo_path
|
32
|
+
@cached_repo_path ||=
|
33
|
+
"#{Vim::Flavor.dot_path}/repos/#{zapped_repo_dir_name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def make_deploy_path(vimfiles_path)
|
37
|
+
"#{vimfiles_path.to_flavors_path()}/#{zapped_repo_dir_name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def clone()
|
41
|
+
message = %x[
|
42
|
+
{
|
43
|
+
git clone '#{@repo_uri}' '#{cached_repo_path}'
|
44
|
+
} 2>&1
|
45
|
+
]
|
46
|
+
if $? != 0 then
|
47
|
+
raise RuntimeError, message
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def fetch()
|
53
|
+
message = %x[
|
54
|
+
{
|
55
|
+
cd #{cached_repo_path.inspect} &&
|
56
|
+
git fetch origin
|
57
|
+
} 2>&1
|
58
|
+
]
|
59
|
+
if $? != 0 then
|
60
|
+
raise RuntimeError, message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def deploy(vimfiles_path)
|
65
|
+
deploy_path = make_deploy_path(vimfiles_path)
|
66
|
+
message = %x[
|
67
|
+
{
|
68
|
+
cd '#{cached_repo_path}' &&
|
69
|
+
git checkout -f '#{locked_version}' &&
|
70
|
+
git checkout-index -a -f --prefix='#{deploy_path}/' &&
|
71
|
+
{
|
72
|
+
vim -u NONE -i NONE -n -N -e -s -c '
|
73
|
+
silent! helptags #{deploy_path}/doc
|
74
|
+
qall!
|
75
|
+
' || true
|
76
|
+
}
|
77
|
+
} 2>&1
|
78
|
+
]
|
79
|
+
if $? != 0 then
|
80
|
+
raise RuntimeError, message
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def undeploy(vimfiles_path)
|
85
|
+
deploy_path = make_deploy_path(vimfiles_path)
|
86
|
+
message = %x[
|
87
|
+
{
|
88
|
+
rm -fr '#{deploy_path}'
|
89
|
+
} 2>&1
|
90
|
+
]
|
91
|
+
if $? != 0 then
|
92
|
+
raise RuntimeError, message
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def list_versions()
|
97
|
+
tags = %x[
|
98
|
+
{
|
99
|
+
cd '#{cached_repo_path}' &&
|
100
|
+
git tag
|
101
|
+
} 2>&1
|
102
|
+
]
|
103
|
+
if $? != 0 then
|
104
|
+
raise RuntimeError, message
|
105
|
+
end
|
106
|
+
|
107
|
+
tags.
|
108
|
+
split(/[\r\n]/).
|
109
|
+
select {|t| t != ''}.
|
110
|
+
map {|t| Gem::Version.create(t)}
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_locked_version()
|
114
|
+
@locked_version =
|
115
|
+
version_contraint.find_the_best_version(list_versions())
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Vim
|
2
|
+
module Flavor
|
3
|
+
class FlavorFile
|
4
|
+
attr_reader :flavors
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@flavors = {}
|
8
|
+
@default_groups = [:default]
|
9
|
+
end
|
10
|
+
|
11
|
+
def interpret(&block)
|
12
|
+
instance_eval(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def eval_flavorfile(flavorfile_path)
|
16
|
+
content = File.open(flavorfile_path, 'rb') do |f|
|
17
|
+
f.read()
|
18
|
+
end
|
19
|
+
interpret do
|
20
|
+
instance_eval(content)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def repo_uri_from_repo_name(repo_name)
|
25
|
+
if /^([^\/]+)$/.match(repo_name) then
|
26
|
+
m = Regexp.last_match
|
27
|
+
"git://github.com/vim-scripts/#{m[1]}.git"
|
28
|
+
elsif /^([A-Za-z0-9_-]+)\/(.*)$/.match(repo_name) then
|
29
|
+
m = Regexp.last_match
|
30
|
+
"git://github.com/#{m[1]}/#{m[2]}.git"
|
31
|
+
elsif /^[a-z]+:\/\/.*$/.match(repo_name) then
|
32
|
+
repo_name
|
33
|
+
else
|
34
|
+
raise "repo_name is written in invalid format: #{repo_name.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def flavor(repo_name, *args)
|
39
|
+
options = Hash === args.last ? args.pop : {}
|
40
|
+
options[:groups] ||= []
|
41
|
+
version_contraint = VersionConstraint.new(args.last || '>= 0')
|
42
|
+
|
43
|
+
f = Flavor.new()
|
44
|
+
f.repo_name = repo_name
|
45
|
+
f.repo_uri = repo_uri_from_repo_name(repo_name)
|
46
|
+
f.version_contraint = version_contraint
|
47
|
+
f.groups = @default_groups + options[:groups]
|
48
|
+
|
49
|
+
@flavors[f.repo_uri] = f
|
50
|
+
end
|
51
|
+
|
52
|
+
def group(*group_names, &block)
|
53
|
+
@default_groups.concat(group_names)
|
54
|
+
yield
|
55
|
+
ensure
|
56
|
+
group_names.each do
|
57
|
+
@default_groups.pop()
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Vim
|
4
|
+
module Flavor
|
5
|
+
class LockFile
|
6
|
+
# TODO: Resolve dependencies recursively.
|
7
|
+
|
8
|
+
attr_reader :flavors, :path
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@flavors = {} # repo_uri => flavor
|
12
|
+
@path = path
|
13
|
+
end
|
14
|
+
|
15
|
+
def load()
|
16
|
+
h = File.open(@path, 'rb') do |f|
|
17
|
+
YAML.load(f.read())
|
18
|
+
end
|
19
|
+
|
20
|
+
@flavors = self.class.flavors_from_poro(h[:flavors])
|
21
|
+
end
|
22
|
+
|
23
|
+
def save()
|
24
|
+
h = {}
|
25
|
+
|
26
|
+
h[:flavors] = self.class.poro_from_flavors(@flavors)
|
27
|
+
|
28
|
+
File.open(@path, 'wb') do |f|
|
29
|
+
YAML.dump(h, f)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.poro_from_flavors(flavors)
|
34
|
+
Hash[
|
35
|
+
flavors.values.map {|f|
|
36
|
+
[
|
37
|
+
f.repo_uri,
|
38
|
+
{
|
39
|
+
:groups => f.groups,
|
40
|
+
:locked_version => f.locked_version.to_s(),
|
41
|
+
:repo_name => f.repo_name,
|
42
|
+
:version_contraint => f.version_contraint.to_s(),
|
43
|
+
}
|
44
|
+
]
|
45
|
+
}
|
46
|
+
]
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.flavors_from_poro(poro)
|
50
|
+
Hash[
|
51
|
+
poro.to_a().map {|repo_uri, h|
|
52
|
+
f = Flavor.new()
|
53
|
+
f.groups = h[:groups]
|
54
|
+
f.locked_version = Gem::Version.create(h[:locked_version])
|
55
|
+
f.repo_name = h[:repo_name]
|
56
|
+
f.repo_uri = repo_uri
|
57
|
+
f.version_contraint = VersionConstraint.new(h[:version_contraint])
|
58
|
+
[f.repo_uri, f]
|
59
|
+
}
|
60
|
+
]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/vim-flavor/version.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Vim
|
2
|
+
module Flavor
|
3
|
+
class VersionConstraint
|
4
|
+
attr_reader :base_version, :operator
|
5
|
+
|
6
|
+
def initialize(s)
|
7
|
+
@base_version, @operator = parse(s)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s()
|
11
|
+
"#{@operator} #{@base_version}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
self.base_version == other.base_version &&
|
16
|
+
self.operator == other.operator
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(s)
|
20
|
+
m = /^\s*(>=|~>)\s+(\S+)$/.match(s)
|
21
|
+
if m then
|
22
|
+
[Gem::Version.create(m[2]), m[1]]
|
23
|
+
else
|
24
|
+
raise "Invalid version constraint: #{s.inspect}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def compatible?(other_version_or_s)
|
29
|
+
v = Gem::Version.create(other_version_or_s)
|
30
|
+
if @operator == '~>' then
|
31
|
+
self.base_version.bump() > v and v >= self.base_version
|
32
|
+
elsif @operator == '>=' then
|
33
|
+
v >= self.base_version
|
34
|
+
else
|
35
|
+
raise NotImplementedError
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_the_best_version(versions)
|
40
|
+
versions.
|
41
|
+
select {|v| compatible?(v)}.
|
42
|
+
sort().
|
43
|
+
reverse().
|
44
|
+
first
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/spec/facade_spec.rb
CHANGED
@@ -250,7 +250,7 @@ describe Vim::Flavor::Facade do
|
|
250
250
|
@flavor = Vim::Flavor::Flavor.new()
|
251
251
|
@flavor.repo_name = '@test_repo_path'
|
252
252
|
@flavor.repo_uri = @test_repo_path
|
253
|
-
@flavor.locked_version = '1.0.0'
|
253
|
+
@flavor.locked_version = Gem::Version.create('1.0.0')
|
254
254
|
|
255
255
|
@flavors = [@flavor]
|
256
256
|
|
data/spec/flavor_spec.rb
CHANGED
@@ -28,7 +28,7 @@ describe Vim::Flavor::Flavor do
|
|
28
28
|
@flavor = described_class.new()
|
29
29
|
@flavor.repo_name = '@test_repo_path'
|
30
30
|
@flavor.repo_uri = @test_repo_path
|
31
|
-
@flavor.locked_version = '1.0.0'
|
31
|
+
@flavor.locked_version = Gem::Version.create('1.0.0')
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should clone the repository into a given path' do
|
@@ -51,7 +51,7 @@ describe Vim::Flavor::Flavor do
|
|
51
51
|
@flavor = described_class.new()
|
52
52
|
@flavor.repo_name = '@test_repo_path'
|
53
53
|
@flavor.repo_uri = @test_repo_path
|
54
|
-
@flavor.locked_version = '1.0.0'
|
54
|
+
@flavor.locked_version = Gem::Version.create('1.0.0')
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'should fail if the repository is not cloned yet' do
|
@@ -91,7 +91,7 @@ describe Vim::Flavor::Flavor do
|
|
91
91
|
@flavor = described_class.new()
|
92
92
|
@flavor.repo_name = '@test_repo_path'
|
93
93
|
@flavor.repo_uri = @test_repo_path
|
94
|
-
@flavor.locked_version = '1.0.0'
|
94
|
+
@flavor.locked_version = Gem::Version.create('1.0.0')
|
95
95
|
|
96
96
|
@vimfiles_path = "#{@tmp_path}/vimfiles"
|
97
97
|
@deploy_path = @flavor.make_deploy_path(@vimfiles_path)
|
@@ -117,7 +117,7 @@ describe Vim::Flavor::Flavor do
|
|
117
117
|
$?.should == 0
|
118
118
|
tag_id = %x{
|
119
119
|
cd #{@flavor.cached_repo_path.inspect} &&
|
120
|
-
git rev-list -n1 #{@flavor.locked_version
|
120
|
+
git rev-list -n1 '#{@flavor.locked_version}'
|
121
121
|
}
|
122
122
|
$?.should == 0
|
123
123
|
head_id.should == tag_id
|
@@ -181,7 +181,7 @@ describe Vim::Flavor::Flavor do
|
|
181
181
|
@flavor = described_class.new()
|
182
182
|
@flavor.repo_name = '@test_repo_path'
|
183
183
|
@flavor.repo_uri = @test_repo_path
|
184
|
-
@flavor.locked_version = '1.0.0'
|
184
|
+
@flavor.locked_version = Gem::Version.create('1.0.0')
|
185
185
|
|
186
186
|
@vimfiles_path = "#{@tmp_path}/vimfiles"
|
187
187
|
@deploy_path = @flavor.make_deploy_path(@vimfiles_path)
|
@@ -209,7 +209,7 @@ describe Vim::Flavor::Flavor do
|
|
209
209
|
@flavor = described_class.new()
|
210
210
|
@flavor.repo_name = '@test_repo_path'
|
211
211
|
@flavor.repo_uri = @test_repo_path
|
212
|
-
@flavor.locked_version = '1.0.0'
|
212
|
+
@flavor.locked_version = Gem::Version.create('1.0.0')
|
213
213
|
end
|
214
214
|
|
215
215
|
it 'should list tags as versions' do
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: vim-flavor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Kana Natsuno
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-04-06 00:00:00 +09:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -53,7 +53,14 @@ files:
|
|
53
53
|
- Rakefile
|
54
54
|
- bin/vim-flavor
|
55
55
|
- lib/vim-flavor.rb
|
56
|
+
- lib/vim-flavor/cli.rb
|
57
|
+
- lib/vim-flavor/facade.rb
|
58
|
+
- lib/vim-flavor/flavor.rb
|
59
|
+
- lib/vim-flavor/flavorfile.rb
|
60
|
+
- lib/vim-flavor/lockfile.rb
|
61
|
+
- lib/vim-flavor/stringextension.rb
|
56
62
|
- lib/vim-flavor/version.rb
|
63
|
+
- lib/vim-flavor/versionconstraint.rb
|
57
64
|
- spec/cli_spec.rb
|
58
65
|
- spec/facade_spec.rb
|
59
66
|
- spec/flavor_spec.rb
|