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