indexer 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.
Files changed (47) hide show
  1. data/.index +54 -0
  2. data/HISTORY.md +9 -0
  3. data/README.md +145 -0
  4. data/bin/index +7 -0
  5. data/data/indexer/r2013/index.kwalify +175 -0
  6. data/data/indexer/r2013/index.yes +172 -0
  7. data/data/indexer/r2013/index.yesi +67 -0
  8. data/data/indexer/r2013/ruby.txt +35 -0
  9. data/data/indexer/r2013/yaml.txt +30 -0
  10. data/lib/indexer.rb +65 -0
  11. data/lib/indexer/attributes.rb +171 -0
  12. data/lib/indexer/command.rb +260 -0
  13. data/lib/indexer/components.rb +8 -0
  14. data/lib/indexer/components/author.rb +140 -0
  15. data/lib/indexer/components/conflict.rb +78 -0
  16. data/lib/indexer/components/copyright.rb +95 -0
  17. data/lib/indexer/components/dependency.rb +18 -0
  18. data/lib/indexer/components/organization.rb +133 -0
  19. data/lib/indexer/components/repository.rb +140 -0
  20. data/lib/indexer/components/requirement.rb +360 -0
  21. data/lib/indexer/components/resource.rb +209 -0
  22. data/lib/indexer/conversion.rb +14 -0
  23. data/lib/indexer/conversion/gemfile.rb +44 -0
  24. data/lib/indexer/conversion/gemspec.rb +114 -0
  25. data/lib/indexer/conversion/gemspec_exporter.rb +304 -0
  26. data/lib/indexer/core_ext.rb +4 -0
  27. data/lib/indexer/error.rb +23 -0
  28. data/lib/indexer/gemfile.rb +75 -0
  29. data/lib/indexer/importer.rb +144 -0
  30. data/lib/indexer/importer/file.rb +94 -0
  31. data/lib/indexer/importer/gemfile.rb +27 -0
  32. data/lib/indexer/importer/gemspec.rb +43 -0
  33. data/lib/indexer/importer/html.rb +289 -0
  34. data/lib/indexer/importer/markdown.rb +45 -0
  35. data/lib/indexer/importer/ruby.rb +47 -0
  36. data/lib/indexer/importer/version.rb +38 -0
  37. data/lib/indexer/importer/yaml.rb +46 -0
  38. data/lib/indexer/loadable.rb +159 -0
  39. data/lib/indexer/metadata.rb +879 -0
  40. data/lib/indexer/model.rb +237 -0
  41. data/lib/indexer/revision.rb +43 -0
  42. data/lib/indexer/valid.rb +287 -0
  43. data/lib/indexer/validator.rb +313 -0
  44. data/lib/indexer/version/constraint.rb +124 -0
  45. data/lib/indexer/version/exceptions.rb +11 -0
  46. data/lib/indexer/version/number.rb +497 -0
  47. metadata +141 -0
@@ -0,0 +1,140 @@
1
+ module Indexer
2
+
3
+ # The Repository class models a packages SCM repository location.
4
+ # It consists of two parts, the `scm` type of repository, it's `url`.
5
+ #
6
+ class Repository < Model
7
+
8
+ # Parse `data` returning a new Repository instance.
9
+ #
10
+ # @param data [String,Array<String>,Array<Hash>,Hash]
11
+ # Repository information.
12
+ #
13
+ # @return [Repository] repository instance
14
+ #--
15
+ # TODO: Should String be allowed, and thus no `id`?
16
+ #++
17
+ def self.parse(data)
18
+ case data
19
+ when String
20
+ new('uri'=>data)
21
+ when Array
22
+ h, d = {}, data.dup # TODO: data.rekey(&:to_s)
23
+ h.update(d.pop) while Hash === d.last
24
+ h['name'] = d.shift.to_s unless d.empty?
25
+ h['uri'] = d.shift.to_s unless d.empty?
26
+ h['scm'] = d.shift.to_s unless d.empty?
27
+ new(h)
28
+ when Hash
29
+ new(data)
30
+ else
31
+ raise(ValidationError, "not a valid repository")
32
+ end
33
+ end
34
+
35
+ #
36
+ # Initialize new Repository instance.
37
+ #
38
+ def initialize(data={})
39
+ super(data)
40
+
41
+ self.scm = infer_scm(uri) unless scm
42
+ end
43
+
44
+ #
45
+ # A name that can be used to identify the purpose of a
46
+ # particular repository.
47
+ #
48
+ attr_reader :name
49
+
50
+ #
51
+ # Set the repository name. This can be any one line description but
52
+ # it generally should be a brief one-word indictor such as "origin"
53
+ # "upstream", "experimental", "joes-fork", etc.
54
+ #
55
+ def name=(name)
56
+ Valid.oneline!(name) # should be word!
57
+ @data[:name] = name.to_str
58
+ end
59
+
60
+ #
61
+ # The repository's URI.
62
+ #
63
+ attr_reader :uri
64
+
65
+ #
66
+ # Set repository URI
67
+ #
68
+ def uri=(uri)
69
+ Valid.oneline!(uri)
70
+ #Valid.uri!(uri) # TODO: any other limitations?
71
+ @data[:scm] = infer_scm(uri)
72
+ @data[:uri] = uri
73
+ end
74
+
75
+ #
76
+ #
77
+ #
78
+ attr_reader :scm
79
+
80
+ #
81
+ # Set the SCM type of repository. The type is a single downcased word.
82
+ # Generally recognized types are:
83
+ #
84
+ # * git
85
+ # * hg
86
+ # * svn
87
+ # * cvs
88
+ # * darcs
89
+ #
90
+ # But any type can be used.
91
+ #
92
+ def scm=(scm)
93
+ Valid.word!(scm)
94
+ @data[:scm] = scm.to_str.downcase
95
+ end
96
+
97
+ #
98
+ # Prefix URI that can be used to link to source code.
99
+ #
100
+ # This name is the traditional one from a time when CVS was the
101
+ # most popular SCM.
102
+ #
103
+ attr_reader :webcvs
104
+
105
+ #
106
+ #
107
+ #
108
+ def webcvs=(uri)
109
+ Valid.oneline!(uri)
110
+ Valid.uri!(uri) # TODO: any other limitations?
111
+ @data[:webcvs] = uri
112
+ end
113
+
114
+ # TODO: Should we rename Repository#webcvs to just #web ?
115
+
116
+ #
117
+ alias_method :web, :webcvs
118
+ alias_method :web=, :webcvs=
119
+
120
+ private
121
+
122
+ #
123
+ def infer_scm(uri)
124
+ case uri
125
+ when /^git:/, /\.git$/
126
+ 'git'
127
+ when /^hg:/, /\.hg$/
128
+ 'hg'
129
+ when /^svn:/
130
+ 'svn'
131
+ when /darcs/
132
+ 'darcs'
133
+ else
134
+ nil
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ end
@@ -0,0 +1,360 @@
1
+ module Indexer
2
+
3
+ # Requirement class.
4
+ #
5
+ # QUESTION: Does Requirement really need to handle multiple version constraints?
6
+ # Currently this only supports one version constraint.
7
+ #
8
+ class Requirement < Model
9
+
10
+ #
11
+ # Parse `data` into a Requirement instance.
12
+ #
13
+ # TODO: What about respond_to?(:to_str) for String, etc.
14
+ #
15
+ def self.parse(data)
16
+ case data
17
+ when String
18
+ parse_string(data)
19
+ when Array
20
+ parse_array(data)
21
+ when Hash
22
+ parse_hash(data)
23
+ else
24
+ raise(ValidationError, "requirement")
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ #
31
+ #
32
+ def self.parse_hash(data)
33
+ name = (data.delete('name') || data.delete(:name)).to_s
34
+ # make sure groups are strings
35
+ groups = []
36
+ groups << (data.delete('groups') || data.delete(:groups))
37
+ groups << (data.delete('group') || data.delete(:group))
38
+ groups = groups.flatten.compact.map{ |g| g.to_s }
39
+ data[:groups] = groups
40
+ #
41
+ new(name, data)
42
+ end
43
+
44
+ #
45
+ #
46
+ def self.parse_string(string)
47
+ case string.strip
48
+ when /^(\w.*?)\s+(.*?)\s*\((.*?)\)$/
49
+ name = $1
50
+ version = $2
51
+ groups = $3
52
+ when /^(\w.*?)\s+(.*?)$/
53
+ name = $1
54
+ version = $2
55
+ groups = nil
56
+ when /^(\w.*?)$/
57
+ name = $1
58
+ version = nil
59
+ groups = nil
60
+ else
61
+ raise(ValidationError, "requirement")
62
+ end
63
+
64
+ version = nil if version.to_s.strip.empty?
65
+ groups = groups.split(/\s*[,;]?\s+/) if groups
66
+
67
+ specifics = {}
68
+ specifics['version'] = version if version
69
+ specifics['groups'] = groups if groups
70
+
71
+ if groups && !groups.empty? && !groups.include?('runtime')
72
+ specifics['development'] = true
73
+ end
74
+
75
+ new(name, specifics)
76
+ end
77
+
78
+ #
79
+ #
80
+ #
81
+ def self.parse_array(array)
82
+ name, data = *array
83
+ case data
84
+ when Hash
85
+ groups = []
86
+ groups << (data.delete('groups') || data.delete(:groups))
87
+ groups << (data.delete('group') || data.delete(:group))
88
+ groups = groups.flatten.compact.map{ |g| g.to_s }
89
+ data[:groups] = groups
90
+
91
+ new(name.to_s, data)
92
+ when String
93
+ parse_string(name + " " + data)
94
+ else
95
+ raise(ValidationError, "requirement")
96
+ end
97
+ end
98
+
99
+ #
100
+ # Create new instance of Requirement.
101
+ #
102
+ def initialize(name, specifics={})
103
+ specifics[:name] = name
104
+ super(specifics)
105
+ end
106
+
107
+ #
108
+ def initialize_attributes
109
+ @data = {
110
+ :groups => [],
111
+ :engines => [],
112
+ :platforms => [],
113
+ :sources => []
114
+ }
115
+ end
116
+
117
+ public
118
+
119
+ #
120
+ #
121
+ attr_reader :name
122
+
123
+ #
124
+ #
125
+ def name=(name)
126
+ @data[:name] = name.to_s
127
+ end
128
+
129
+ #
130
+ # The requirement's version constraint.
131
+ #
132
+ # @return [Version::Constraint] version constraint.
133
+ #
134
+ attr_reader :version
135
+
136
+ #
137
+ # Set the version constraint.
138
+ #
139
+ # @param version [String,Array,Version::Constraint]
140
+ # Version constraint(s)
141
+ #
142
+ def version=(version)
143
+ @data[:version] = Version::Constraint.parse(version)
144
+ end
145
+
146
+ #
147
+ alias :versions= :version=
148
+
149
+ #
150
+ # Returns true if the requirement is a development requirement.
151
+ #
152
+ # @return [Boolean] development requirement?
153
+ def development?
154
+ @data[:development]
155
+ end
156
+
157
+ #
158
+ # Set the requirement's development flag.
159
+ #
160
+ # @param [Boolean] true/false development requirement
161
+ #
162
+ def development=(boolean)
163
+ @data[:development] = !!boolean
164
+ end
165
+
166
+ #
167
+ # Return `true` if requirement is a runtime requirement.
168
+ #
169
+ # @return [Boolean] runtime requirement?
170
+ def runtime?
171
+ ! @data[:development]
172
+ end
173
+
174
+ #
175
+ # The groups to which the requirement belongs.
176
+ #
177
+ # @return [Array] list of groups
178
+ #
179
+ attr_reader :groups
180
+
181
+ #
182
+ # Set the groups to which the requirement belongs.
183
+ #
184
+
185
+ # @return [Array, String] list of groups
186
+ #
187
+ def groups=(groups)
188
+ @data[:groups] = [groups].flatten
189
+ end
190
+
191
+ # Singular alias for #groups.
192
+ alias :group :groups
193
+ alias :group= :groups=
194
+
195
+ #
196
+ # Is the requirment optional? An optional requirement is recommended
197
+ # but not strictly necessary.
198
+ #
199
+ # @return [Boolean] optional requirement?
200
+ #
201
+ def optional?
202
+ @data[:optional]
203
+ end
204
+
205
+ #
206
+ # Set optional.
207
+ #
208
+ # @param [Boolean] optional requirement?
209
+ #
210
+ def optional=(boolean)
211
+ @data[:optional] = !!boolean
212
+ end
213
+
214
+ #
215
+ # Is the requirment external? An external requirement is one that is only
216
+ # available outside the expected packaging system. For a Ruby application, for example,
217
+ # this would be library not available via rubygems.org, such as a C library that is only
218
+ # avaialble via an operating system's package manager or via a direct download using the
219
+ # "make; make install" compile and installation procedure.
220
+ #
221
+ # @return [Boolean] external requirement?
222
+ #
223
+ def external?
224
+ @data[:external]
225
+ end
226
+
227
+ #
228
+ # Set external.
229
+ #
230
+ # @param [Boolean] external requirement?
231
+ #
232
+ def external=(boolean)
233
+ @data[:external] = !!boolean
234
+ end
235
+
236
+ #
237
+ # Applies only for specified Ruby engines. Each entry can be
238
+ # the `RUBY_ENGINE` value and optionally a version constraint
239
+ # on `RUBY_VERSION`.
240
+ #
241
+ # @return [Array] name and version constraint
242
+ #
243
+ attr :engines
244
+
245
+ #
246
+ # Applies only for specified Ruby engines. Each entry can be
247
+ # the `RUBY_ENGINE` value and optionally a version constraint
248
+ # on `RUBY_VERSION`.
249
+ #
250
+ # @example
251
+ #
252
+ # requirement.engines = [
253
+ # 'ruby 1.8~'
254
+ # ]
255
+ #
256
+ def engines=(engines)
257
+ @data['engines'] = Array(engines).map do |engine|
258
+ case engine
259
+ when String
260
+ name, vers = engine.strip.split(/\s+/)
261
+ vers = nil if vers.empty?
262
+ when Array
263
+ name, vers = *engine
264
+ when Hash
265
+ name = engine['name']
266
+ vers = engine['version']
267
+ end
268
+ e = {}
269
+ e['name'] = name
270
+ e['version'] = Version::Constraint.parse(vers) if vers
271
+ e
272
+ end
273
+ end
274
+
275
+ alias_method :engine, :engines
276
+ alias_method :engine=, :engines=
277
+
278
+ attr :platforms
279
+
280
+ #
281
+ # Applies only for specified platforms. The platform must be verbatim
282
+ # `RUBY_PLATFORM` value.
283
+ #
284
+ # @example
285
+ # requirement.platforms = ['x86_64-linux']
286
+ #
287
+ def platforms=(platforms)
288
+ @data[:platforms] = Array(platforms)
289
+ end
290
+
291
+ alias_method :platform, :platforms
292
+ alias_method :platform=, :platforms=
293
+
294
+ #
295
+ # The public repository resource in which the requirement source code
296
+ # can be found.
297
+ #
298
+ attr :repository
299
+
300
+ #
301
+ # Set the public repository resource in which the requirement
302
+ # source code can be found.
303
+ #
304
+ def repository=(repository)
305
+ @data[:repository] = Repository.parse(repository)
306
+ end
307
+
308
+ alias :repo :repository
309
+ alias :repo= :repository=
310
+
311
+ #
312
+ # Places from which the requirement can be obtained. Generally a source
313
+ # should be a URI, but there is no strict requirement. It can be as
314
+ # simple as a name, e.g. `rubygems` or as specific as a URL to a downloadable
315
+ # `.zip` package.
316
+ #
317
+ # @example
318
+ # requirement.sources = ['http://rubygems.org']
319
+ #
320
+ attr :sources
321
+
322
+ #
323
+ # Set sources.
324
+ #
325
+ def sources=(sources)
326
+ @data[:sources] = Array(sources)
327
+ end
328
+
329
+ #
330
+ # Convert to canonical hash.
331
+ #
332
+ def to_h
333
+ h = super
334
+
335
+ h['version'] = version.to_s if version
336
+ h['repository'] = repository.to_h if repository
337
+
338
+ h.delete('groups') if h['groups'] && h['groups'].empty?
339
+ h.delete('engines') if h['engines'] && h['engines'].empty?
340
+ h.delete('platforms') if h['platforms'] && h['platforms'].empty?
341
+ h.delete('sources') if h['sources'] && h['sources'].empty?
342
+
343
+ h
344
+ end
345
+
346
+ private
347
+
348
+ # ensure engine entries are strings
349
+ #def engines_to_h
350
+ # engines.map do |engine|
351
+ # hash = {}
352
+ # hash['name'] = engine['name']
353
+ # hash['version'] = engine['version'].to_s
354
+ # hash
355
+ # end
356
+ #end
357
+
358
+ end
359
+
360
+ end