library 0.1.0
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/.ruby +57 -0
- data/.yardopts +6 -0
- data/COPYING.rdoc +30 -0
- data/HISTORY.rdoc +13 -0
- data/README.md +177 -0
- data/lib/library.rb +532 -0
- data/lib/library/autoload.rb +14 -0
- data/lib/library/core_ext.rb +34 -0
- data/lib/library/domain.rb +244 -0
- data/lib/library/errors.rb +49 -0
- data/lib/library/feature.rb +207 -0
- data/lib/library/kernel.rb +81 -0
- data/lib/library/ledger.rb +642 -0
- data/lib/library/metadata.rb +398 -0
- data/lib/library/rbconfig.rb +65 -0
- data/lib/library/rubygems.rb +19 -0
- data/lib/library/rubylib.rb +206 -0
- data/lib/library/version.rb +387 -0
- data/lib/ubylibs.rb +8 -0
- data/qed/01_loading.rdoc +14 -0
- data/qed/02_library.rdoc +55 -0
- data/qed/03_ledger.rdoc +30 -0
- data/qed/04_version.rdoc +101 -0
- data/qed/applique/check.rb +11 -0
- data/qed/applique/project.rb +34 -0
- data/qed/fixtures/foo/.ruby +5 -0
- data/qed/fixtures/foo/lib/foo.rb +1 -0
- data/qed/fixtures/tryme/1.0/.ruby +6 -0
- data/qed/fixtures/tryme/1.0/lib/tryme.rb +1 -0
- data/qed/fixtures/tryme/1.1/.ruby +7 -0
- data/qed/fixtures/tryme/1.1/lib/tryme.rb +1 -0
- data/qed/helpers/new_project.rdoc +29 -0
- data/qed/helpers/projects.rdoc +56 -0
- data/test/case_ledger.rb +23 -0
- data/test/case_library.rb +13 -0
- data/test/case_version.rb +89 -0
- data/test/fixture/.ruby +56 -0
- data/test/fixture/lib/foo.rb +7 -0
- data/test/helper.rb +2 -0
- metadata +144 -0
@@ -0,0 +1,398 @@
|
|
1
|
+
class Library
|
2
|
+
|
3
|
+
# The Metadata call encapsulates a library's information, in particular
|
4
|
+
# `name`, `version` and `load_path`.
|
5
|
+
#
|
6
|
+
class Metadata
|
7
|
+
|
8
|
+
#
|
9
|
+
# Setup new metadata object.
|
10
|
+
#
|
11
|
+
# @param [String] location
|
12
|
+
# Location of project on disc.
|
13
|
+
#
|
14
|
+
# @param [Hash] metadata
|
15
|
+
# Manual metadata settings.
|
16
|
+
#
|
17
|
+
# @option metadata [Boolean] :load
|
18
|
+
# Set to +false+ will prevent metadata being loaded
|
19
|
+
# from .ruby or .gemspec file, but a LoadError will
|
20
|
+
# be raised without `:name` and `:version`.
|
21
|
+
#
|
22
|
+
def initialize(location, metadata={})
|
23
|
+
@location = location
|
24
|
+
|
25
|
+
@load = metadata.delete(:load)
|
26
|
+
@load = true if @load.nil? # default is true
|
27
|
+
|
28
|
+
@data = {}
|
29
|
+
|
30
|
+
update(metadata)
|
31
|
+
|
32
|
+
if @load
|
33
|
+
if not (@data['name'] && @data['version'] && @data['load_path'])
|
34
|
+
load_metadata
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise LoadError unless data['name'] && data['version'] # todo: just name ?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Update metadata with data hash.
|
43
|
+
#
|
44
|
+
# @param [Hash] data
|
45
|
+
# Data to merge into metadata table.
|
46
|
+
#
|
47
|
+
def update(data)
|
48
|
+
data = data.rekey
|
49
|
+
|
50
|
+
@data.update(data)
|
51
|
+
|
52
|
+
self.name = data[:name] if data[:name]
|
53
|
+
self.version = data[:version] if data[:version]
|
54
|
+
self.load_path = data[:load_path] if data[:load_path]
|
55
|
+
self.date = data[:date] if data[:date]
|
56
|
+
self.omit = data[:omit]
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Location of library.
|
61
|
+
#
|
62
|
+
attr :location
|
63
|
+
|
64
|
+
#
|
65
|
+
# Local load paths.
|
66
|
+
#
|
67
|
+
def load_path
|
68
|
+
@data[:load_path] || ['lib']
|
69
|
+
end
|
70
|
+
|
71
|
+
alias_method :loadpath, :load_path
|
72
|
+
|
73
|
+
#
|
74
|
+
# Set the loadpath.
|
75
|
+
#
|
76
|
+
def load_path=(path)
|
77
|
+
case path
|
78
|
+
when nil
|
79
|
+
path = ['lib']
|
80
|
+
when String
|
81
|
+
path = path.strip.split(/[,;:\ \n\t]/).map{|s| s.strip}
|
82
|
+
end
|
83
|
+
@data[:load_path] = path
|
84
|
+
end
|
85
|
+
|
86
|
+
alias_method :loadpath=, :load_path=
|
87
|
+
|
88
|
+
#
|
89
|
+
# Name of library.
|
90
|
+
#
|
91
|
+
def name
|
92
|
+
@data[:name]
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Set name.
|
97
|
+
#
|
98
|
+
def name=(string)
|
99
|
+
@data[:name] = string.to_s if string
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Version number.
|
104
|
+
#
|
105
|
+
# Technically, a library should not appear in a ledger list if it lacks
|
106
|
+
# a version. However, just in case this occurs (say by a hand edited
|
107
|
+
# environment) we fallback to a version of '0.0.0'.
|
108
|
+
#
|
109
|
+
def version
|
110
|
+
@data[:version] ||= Version.new('0.0.0')
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Set version, converts string into Version number class.
|
115
|
+
#
|
116
|
+
def version=(string)
|
117
|
+
@data[:version] = Version.new(string) if string
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Release date.
|
122
|
+
#
|
123
|
+
def date
|
124
|
+
@data[:date] || (load_metadata; @data[:data])
|
125
|
+
end
|
126
|
+
|
127
|
+
alias_method :released, :date
|
128
|
+
|
129
|
+
# TODO: Should we convert date to Time object?
|
130
|
+
|
131
|
+
#
|
132
|
+
# Set the date.
|
133
|
+
#
|
134
|
+
def date=(date)
|
135
|
+
@data[:date] = date
|
136
|
+
end
|
137
|
+
|
138
|
+
alias_method :released=, :date=
|
139
|
+
|
140
|
+
#
|
141
|
+
# Runtime and development requirements combined.
|
142
|
+
#
|
143
|
+
def requirements
|
144
|
+
@data[:requirements] || (load_metadata; @data[:requirements])
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Runtime requirements.
|
149
|
+
#
|
150
|
+
def runtime_requirements
|
151
|
+
@runtime_requirements ||= requirements.reject{ |r| r['development'] }
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Development requirements.
|
156
|
+
#
|
157
|
+
def development_requirements
|
158
|
+
@development_requirements ||= requirements.select{ |r| r['development'] }
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Access to non-primary metadata.
|
163
|
+
#
|
164
|
+
def [](name)
|
165
|
+
@data[name.to_sym]
|
166
|
+
end
|
167
|
+
|
168
|
+
# TODO: Should we support +omit+ setting, or should we add a way to
|
169
|
+
# exclude loctions via environment setting?
|
170
|
+
|
171
|
+
#
|
172
|
+
# Omit from any ledger?
|
173
|
+
#
|
174
|
+
def omit?
|
175
|
+
@omit
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Set omit.
|
180
|
+
#
|
181
|
+
def omit=(boolean)
|
182
|
+
@omit = boolean
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
# Does this location have .ruby entries?
|
187
|
+
#
|
188
|
+
def dotruby?
|
189
|
+
@_dotruby ||= File.exist?(File.join(location, '.ruby'))
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Deterime if the location is a gem location. It does this by looking
|
194
|
+
# for the corresponding `gems/specification/*.gemspec` file.
|
195
|
+
#
|
196
|
+
def gemspec?
|
197
|
+
#return true if Dir[File.join(location, '*.gemspec')].first
|
198
|
+
pkgname = File.basename(location)
|
199
|
+
gemsdir = File.dirname(location)
|
200
|
+
specdir = File.join(File.dirname(gemsdir), 'specifications')
|
201
|
+
Dir[File.join(specdir, "#{pkgname}.gemspec")].first
|
202
|
+
end
|
203
|
+
|
204
|
+
#
|
205
|
+
# Access to complete gemspec. This is for use with extended metadata.
|
206
|
+
#
|
207
|
+
def gemspec
|
208
|
+
@_gemspec ||= (
|
209
|
+
require 'rubygems'
|
210
|
+
::Gem::Specification.load(gemspec_file)
|
211
|
+
)
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# Verify that a library's requirements are all available in the ledger.
|
216
|
+
# Returns a list of `[name, version]` of Libraries that were not found.
|
217
|
+
#
|
218
|
+
# @return [Array<String,String>] List of missing requirements.
|
219
|
+
#
|
220
|
+
def missing_requirements(development=false) #verbose=false)
|
221
|
+
libs, fail = [], []
|
222
|
+
reqs = development ? requirements : runtime_requirements
|
223
|
+
reqs.each do |req|
|
224
|
+
name = req['name']
|
225
|
+
vers = req['version']
|
226
|
+
lib = Library[name, vers]
|
227
|
+
if lib
|
228
|
+
libs << lib
|
229
|
+
#$stdout.puts " [LOAD] #{name} #{vers}" if verbose
|
230
|
+
unless libs.include?(lib) or fail.include?([lib,vers])
|
231
|
+
lib.verify_requirements(development) #verbose)
|
232
|
+
end
|
233
|
+
else
|
234
|
+
fail << [name, vers]
|
235
|
+
#$stdout.puts " [FAIL] #{name} #{vers}" if verbose
|
236
|
+
end
|
237
|
+
end
|
238
|
+
return fail
|
239
|
+
end
|
240
|
+
|
241
|
+
#
|
242
|
+
# Like {#missing_requirements} but returns `true`/`false`.
|
243
|
+
#
|
244
|
+
def missing_requirements?(development=false)
|
245
|
+
list = missing_requirements(development=false)
|
246
|
+
list.empty? ? false : true
|
247
|
+
end
|
248
|
+
|
249
|
+
#
|
250
|
+
# Returns hash of primary metadata.
|
251
|
+
#
|
252
|
+
# @return [Hash] primary metdata
|
253
|
+
#
|
254
|
+
def to_h
|
255
|
+
{ 'location' => location,
|
256
|
+
'name' => name,
|
257
|
+
'version' => version.to_s,
|
258
|
+
'date' => date.to_s,
|
259
|
+
'load_path' => load_path,
|
260
|
+
'requirements' => requirements,
|
261
|
+
'omit' => omit
|
262
|
+
}
|
263
|
+
end
|
264
|
+
|
265
|
+
private
|
266
|
+
|
267
|
+
# Load metadata.
|
268
|
+
def load_metadata
|
269
|
+
return unless @load
|
270
|
+
|
271
|
+
if dotruby?
|
272
|
+
load_dotruby
|
273
|
+
elsif gemspec?
|
274
|
+
load_gemspec
|
275
|
+
end
|
276
|
+
|
277
|
+
@load = false # loading is complete
|
278
|
+
end
|
279
|
+
|
280
|
+
# Load metadata for .ruby file.
|
281
|
+
def load_dotruby
|
282
|
+
require 'yaml'
|
283
|
+
|
284
|
+
data = YAML.load_file(File.join(location, '.ruby'))
|
285
|
+
|
286
|
+
update(data)
|
287
|
+
|
288
|
+
#if Hash === data
|
289
|
+
# self.name = data['name']
|
290
|
+
# self.version = data['version'] #|| '0.0.0'
|
291
|
+
# self.load_path = data['load_path'] || ['lib']
|
292
|
+
#
|
293
|
+
# self.title = data['title'] || data['name'].capitalize
|
294
|
+
# self.date = data['date']
|
295
|
+
#
|
296
|
+
# reqs = data['requirements'] || []
|
297
|
+
# reqs.each do |req|
|
298
|
+
# if req['development']
|
299
|
+
# self.development_requirements << [req['name'], req['version']]
|
300
|
+
# else
|
301
|
+
# self.runtime_requirements << [req['name'], req['version']]
|
302
|
+
# end
|
303
|
+
# end
|
304
|
+
#end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Load metadata from a gemspec. This is a fallback option. It is highly
|
308
|
+
# recommended that a project have a `.ruby` file instead.
|
309
|
+
#
|
310
|
+
# This method requires that the `dotruby` gem be installed.
|
311
|
+
#
|
312
|
+
def load_gemspec
|
313
|
+
#require 'rubygems'
|
314
|
+
require 'dotruby/rubygems'
|
315
|
+
|
316
|
+
text = File.read(gemspec_file)
|
317
|
+
if text =~ /\A---/ # TODO: improve
|
318
|
+
require 'yaml'
|
319
|
+
spec = YAML.load(text)
|
320
|
+
else
|
321
|
+
spec = eval(text)
|
322
|
+
end
|
323
|
+
|
324
|
+
dotruby = DotRuby::Spec.parse_gemspec(spec)
|
325
|
+
|
326
|
+
data = dotruby.to_h
|
327
|
+
|
328
|
+
udpate(data)
|
329
|
+
|
330
|
+
return
|
331
|
+
|
332
|
+
#self.name = spec.name
|
333
|
+
#self.version = spec.version.to_s
|
334
|
+
#self.load_path = spec.require_paths
|
335
|
+
#self.date = spec.date
|
336
|
+
#self.title = spec.name.capitalize # for lack of better way
|
337
|
+
|
338
|
+
#spec.dependencies.each do |dep|
|
339
|
+
# if dep.development?
|
340
|
+
# self.development_requirements < [dep.name, dep.version]
|
341
|
+
# else
|
342
|
+
# self.runtime_requirements < [dep.name, dep.verison]
|
343
|
+
# end
|
344
|
+
#end
|
345
|
+
end
|
346
|
+
|
347
|
+
#
|
348
|
+
# Returns the path to the .gemspec file.
|
349
|
+
#
|
350
|
+
def gemspec_file
|
351
|
+
gemspec_system_file || gemspec_local_file
|
352
|
+
end
|
353
|
+
|
354
|
+
#
|
355
|
+
# Returns the path to a gemspec file located in the project location,
|
356
|
+
# if it exists. Otherwise returns +nil+.
|
357
|
+
#
|
358
|
+
def gemspec_file_local
|
359
|
+
@_gemspec_file_local ||= Dir[File.join(location, '*.gemspec')].first
|
360
|
+
end
|
361
|
+
|
362
|
+
#
|
363
|
+
# Returns the path to a gemspec file located in the gems/specifications
|
364
|
+
# directory, if it exists. Otherwise returns +nil+.
|
365
|
+
#
|
366
|
+
def gemspec_file_system
|
367
|
+
@_gemspec_file_system ||= (
|
368
|
+
pkgname = File.basename(location)
|
369
|
+
gemsdir = File.dirname(location)
|
370
|
+
specdir = File.join(File.dirname(gemsdir), 'specifications')
|
371
|
+
Dir[File.join(specdir, "#{pkgname}.gemspec")].first
|
372
|
+
)
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
|
381
|
+
# Fake
|
382
|
+
#module Gem
|
383
|
+
# class Specification < Hash
|
384
|
+
# def initialize
|
385
|
+
# yield(self)
|
386
|
+
# end
|
387
|
+
# def method_missing(s,v=nil,*a,&b)
|
388
|
+
# case s.to_s
|
389
|
+
# when /=$/
|
390
|
+
# self[s.to_s.chomp('=').to_sym] = v
|
391
|
+
# else
|
392
|
+
# self[s]
|
393
|
+
# end
|
394
|
+
# end
|
395
|
+
# end
|
396
|
+
#end
|
397
|
+
|
398
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
module ::RbConfig
|
4
|
+
|
5
|
+
#
|
6
|
+
# Return the path to the data directory associated with the given
|
7
|
+
# library name.
|
8
|
+
#
|
9
|
+
# Normally this is just:
|
10
|
+
#
|
11
|
+
# "#{Config::CONFIG['datadir']}/#{name}"
|
12
|
+
#
|
13
|
+
# But it may be modified by packages like RubyGems and Rolls to handle
|
14
|
+
# versioned data directories.
|
15
|
+
#
|
16
|
+
def self.datadir(name, versionless=false)
|
17
|
+
if lib = Library.instance(name)
|
18
|
+
lib.datadir(versionless)
|
19
|
+
elsif defined?(super)
|
20
|
+
super(name)
|
21
|
+
else
|
22
|
+
File.join(CONFIG['datadir'], name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Return the path to the configuration directory.
|
28
|
+
#
|
29
|
+
def self.confdir(name)
|
30
|
+
if lib = Roll::Library.instance(name)
|
31
|
+
lib.confdir
|
32
|
+
else
|
33
|
+
File.join(CONFIG['confdir'], name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Patterns used to identiy a Windows platform.
|
39
|
+
#
|
40
|
+
WIN_PATTERNS = [
|
41
|
+
/bccwin/i,
|
42
|
+
/cygwin/i,
|
43
|
+
/djgpp/i,
|
44
|
+
/mingw/i,
|
45
|
+
/mswin/i,
|
46
|
+
/wince/i,
|
47
|
+
]
|
48
|
+
|
49
|
+
#WINDOWS_PLATFORM = !!WIN_PATTERNS.find{ |r| RUBY_PLATFORM =~ r }
|
50
|
+
|
51
|
+
#
|
52
|
+
# Is this a windows platform? This method compares the entires
|
53
|
+
# in +WIN_PATTERNS+ against +RUBY_PLATFORM+.
|
54
|
+
#
|
55
|
+
def self.windows_platform?
|
56
|
+
case RUBY_PLATFORM
|
57
|
+
when *WIN_PATTERNS
|
58
|
+
true
|
59
|
+
else
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|