indexer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,67 @@
1
+ ---
2
+ HEADER-DIVISION:
3
+ apply-tag: "!http://rubyworks.github.org/dotruby"
4
+ description:
5
+ Specification for canonical .ruby files.
6
+ author: trans <transfire@gmail.com>
7
+
8
+ TEMPLATE-DIVISION:
9
+ revision : PIC ZZ9; TAG !!int; REQ true
10
+ name : PIC AW[29]; REQ true
11
+ version : PIC ZZ9{.ZZ9}[5]; REX semver
12
+ codename : PIC X[30]
13
+ title : PIC X[30]
14
+ date : PIC 9999-99-99{_99:99:99}[0,1]
15
+ created : PIC 9999-99-99{_99:99:99}[0,1]
16
+ summary : PIC X[79]
17
+ description: PIC X[1000]
18
+ authors:
19
+ - name : PIC X[30]
20
+ email : REX email
21
+ url : REX url
22
+ roles :
23
+ - PIC X[30]
24
+ suite: PIC X[30]
25
+ organization: PIC X[30]
26
+ copyrights:
27
+ - holder : PIC X[30]
28
+ year : PIC 9999{-9999}[0,1]
29
+ license : PIC W[30]
30
+ requirements: &r
31
+ - name: PIC W[30]
32
+ version: REX //
33
+ groups:
34
+ - PIC W[30]
35
+ development: TAG !!bool
36
+ optional: TAG !!bool
37
+ engine:
38
+ - name: PIC W[30]
39
+ version: PIC W[30]
40
+ platform:
41
+ - PIC W[30]
42
+ repository:
43
+ name: PIC W[30]
44
+ uri: REX uri
45
+ scm: PIC W[15]
46
+ dependencies: *r
47
+ conflicts:
48
+ - name: PIC W[30]
49
+ version: PIC X[30]
50
+ substitues:
51
+ - PIC W[30]
52
+ replaces:
53
+ - PIC W[30]
54
+ resources:
55
+ - name: PIC X[30]
56
+ uri: REX uri
57
+ repositories:
58
+ - name: PIC X[30]
59
+ uri: REX uri
60
+ scm: PIC W[30]
61
+ load_path:
62
+ - REX file; DEF 'lib'
63
+ install_message: PIC X[1000]
64
+ extra: {}
65
+
66
+ CONSTRAINTS-DIVISION: {}
67
+
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ name <%= name.inspect %>
4
+ version <%= version.inspect %>
5
+ title <%= title.inspect %>
6
+ summary <%= summary.inspect %>
7
+
8
+ description \
9
+ <% description.inspect %>
10
+
11
+ authors [
12
+ 'you <you@foomail.com>'
13
+ ]
14
+
15
+ requirements [
16
+ 'foo 1.0~',
17
+ 'rake (build)',
18
+ 'test (test)'
19
+ ]
20
+
21
+ repositories {
22
+ 'upstream' => 'http://github.com/organization/app_name/<%= name %>.git'
23
+ }
24
+
25
+ resources {
26
+ 'home' => 'http://organization.github.org/<%= name %>',
27
+ 'code' => 'http://github.com/organization/<%= name %>'
28
+ }
29
+
30
+ categories ['foo']
31
+
32
+ copyrights: [
33
+ '2012 Your Name (MIT)'
34
+ ]
35
+
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: <%= name %>
3
+ version: <%= version %>
4
+ title: <%= title %>
5
+ summary: <%= summary %>
6
+
7
+ description:
8
+ <%= description %>
9
+
10
+ authors:
11
+ - you <you@foomail.com>
12
+
13
+ requirements:
14
+ - dependency 1.0~
15
+ - rake (build)
16
+ - test (test)
17
+
18
+ repositories:
19
+ upstream: http://github.com/organization/app_name/app_name.git
20
+
21
+ resources:
22
+ home: http://organization.github.org/app_name
23
+ code: http://github.com/organization/app_name
24
+
25
+ categories:
26
+ - foo
27
+
28
+ copyrights:
29
+ - 2012 Your Name (MIT)
30
+
@@ -0,0 +1,65 @@
1
+ module Indexer
2
+ # Name of this program.
3
+ NAME = 'indexer'
4
+
5
+ # Current stable revision of the specification (by year).
6
+ REVISION = 2013
7
+
8
+ # File name of locked metadata file.
9
+ LOCK_FILE = '.index'
10
+
11
+ # Default metadata file name for use by end-developer.
12
+ USER_FILES = '{Indexfile,Indexfile.rb,Metadata,Metadata.yml,Metadata.yaml}'
13
+
14
+ # Indexer library directory.
15
+ LIBDIR = File.dirname(__FILE__) + '/indexer'
16
+
17
+ # Indexer library directory.
18
+ DATADIR = File.dirname(__FILE__) + '/../data/indexer'
19
+
20
+ # Metadata from the project's `indexer.yml` index file.
21
+ # This is used as a fallback for #const_missing.
22
+ #
23
+ # Returns [Hash] of metadata.
24
+ def self.index
25
+ @index ||= (
26
+ require 'yaml'
27
+ dir = File.dirname(__FILE__)
28
+ file = Dir[File.join(dir, "{#{NAME}.yml,../.index}")].first
29
+ file ? YAML.load_file(file) : {}
30
+ )
31
+ end
32
+
33
+ # Project metadata via RubyGems, fallback to index file.
34
+ #
35
+ # TODO: The #to_s on the gemspec return value is a bit too simplistic. But how to fix?
36
+ # The goal is reduce the value to a basic type (String, Hash, Array, Numeric).
37
+ #
38
+ def self.const_missing(const_name)
39
+ name = const_name.to_s.downcase
40
+ begin
41
+ Gem.loaded_specs[NAME].send(name).to_s
42
+ rescue StandardError
43
+ index[name] || super(const_name)
44
+ end
45
+ end
46
+ end
47
+
48
+ require 'yaml'
49
+ require 'time'
50
+
51
+ require 'indexer/version/exceptions'
52
+ require 'indexer/version/number'
53
+ require 'indexer/version/constraint'
54
+
55
+ require 'indexer/core_ext'
56
+ require 'indexer/command'
57
+ require 'indexer/error'
58
+ require 'indexer/valid'
59
+ require 'indexer/revision'
60
+
61
+ require 'indexer/model'
62
+ require 'indexer/components'
63
+ require 'indexer/metadata'
64
+ require 'indexer/importer'
65
+
@@ -0,0 +1,171 @@
1
+ module Indexer
2
+
3
+ # Tracks supported attributes.
4
+ def self.attributes
5
+ @attributes ||= []
6
+ end
7
+
8
+ # The Attributes module defines all of the accepted metadata fields.
9
+ module Attributes
10
+
11
+ # Define attribute, plus track it.
12
+ def self.attr_accessor(name)
13
+ Indexer.attributes << name.to_sym
14
+
15
+ class_eval %{
16
+ def #{name}
17
+ @data[:#{name}]
18
+ end
19
+ def #{name}=(val)
20
+ @data[:#{name}] = val
21
+ end
22
+ }
23
+ end
24
+
25
+ #
26
+ def attributes
27
+ Indexer.attributes
28
+ end
29
+
30
+ # The revision of ruby meta specification.
31
+ attr_accessor :revision
32
+
33
+ #def revision
34
+ # REVISION
35
+ #end
36
+
37
+ # The type of ruby meta specification.
38
+ attr_accessor :type
39
+
40
+ # Files from which to import metadata.
41
+ attr_accessor :sources
42
+
43
+ # The name of the project
44
+ attr_accessor :name
45
+
46
+ # The version of the project
47
+ attr_accessor :version
48
+
49
+ # The nick name for the particular version, e.g. "Lucid Lynx".
50
+ attr_accessor :codename
51
+
52
+ # The date of this version.
53
+ attr_accessor :date
54
+
55
+ # The project title
56
+ attr_accessor :title
57
+
58
+ # The project summary
59
+ attr_accessor :summary
60
+
61
+ # The project description
62
+ attr_accessor :description
63
+
64
+ # The suite to which the project belongs.
65
+ attr_accessor :suite
66
+
67
+ # The copyrights and licenses of the project.
68
+ attr_accessor :copyrights
69
+
70
+ # The authors of the project
71
+ # The first author should be the primary contact.
72
+ attr_accessor :authors
73
+
74
+ # The organizations involved with the project.
75
+ attr_accessor :organizations
76
+
77
+ # The resource locators for the project.
78
+ attr_accessor :resources
79
+
80
+ # The repository URLs for the project.
81
+ attr_accessor :repositories
82
+
83
+ # TODO: Might webcvs simply be taken from the first repository instead?
84
+
85
+ # URI for linking to source code.
86
+ attr_accessor :webcvs
87
+
88
+ # The directories to search within the project when requiring files
89
+ attr_accessor :load_path # :loadpath or :require_paths ?
90
+
91
+ # List of language engine/version family supported.
92
+ attr_accessor :engines
93
+
94
+ # List of platforms supported.
95
+ attr_accessor :platforms
96
+
97
+ # The names of the executable scripts
98
+ # NOTE: Do not need, executable should alwasy by in bin/, right?
99
+ #attr_accessor :executables
100
+
101
+ # The packages this package requires to function.
102
+ attr_accessor :requirements #:dependencies
103
+
104
+ # A list of packages that provide more or less the same functionality.
105
+ # A good example is for a markdown library.
106
+ #
107
+ # alternatives:
108
+ # - rdiscount
109
+ # - redcarpet
110
+ # - BlueCloth
111
+ #
112
+ attr_accessor :alternatives
113
+
114
+ # The packages with which this project cannot function.
115
+ attr_accessor :conflicts
116
+
117
+ #
118
+ # NOTE: This is a Debian concept. Is it useful?
119
+ #attr_accessor :provides
120
+
121
+ # Categories can be used to help clarify the purpose of
122
+ # a project, e.g. `testing` or `rest`. There are no standard
123
+ # categories, just use common sense. Categories must be single-line
124
+ # strings. When comparisons are made they will be downcased.
125
+ attr_accessor :categories
126
+
127
+ # The version of Ruby required by the project
128
+ # NOTE: is it possible to to makes this a part of ordinary requirements?
129
+ #attr_accessor :required_ruby_version
130
+
131
+ # The post-installation message.
132
+ attr_accessor :install_message
133
+
134
+ # The date the project was started.
135
+ attr_accessor :created
136
+
137
+ # The toplevel namespace of API, e.g. `module Foo` or `class Bar`.
138
+ # NOTE: how to best handle this?
139
+ attr_accessor :namespace
140
+
141
+ # Any user-defined extraneous metadata.
142
+ #attr_accessor :extra
143
+
144
+ protected
145
+
146
+ #
147
+ # Initializes the {Metadata} attributes.
148
+ #
149
+ # @todo Is it okay to default type to `ruby`?
150
+ #
151
+ def initialize_attributes
152
+ @data = {
153
+ :revision => REVISION,
154
+ :type => 'ruby',
155
+ :sources => [],
156
+ :authors => [],
157
+ :organizations => [],
158
+ :copyrights => [],
159
+ :alternatives => [],
160
+ :requirements => [],
161
+ :conflicts => [],
162
+ :repositories => [],
163
+ :resources => [],
164
+ :categories => [],
165
+ :load_path => ['lib']
166
+ }
167
+ end
168
+
169
+ end
170
+
171
+ end
@@ -0,0 +1,260 @@
1
+ module Indexer
2
+
3
+ # Command line interface.
4
+ #
5
+ class Command
6
+
7
+ #
8
+ # Shortcut to `new.run(argv)`.
9
+ #
10
+ def self.run(argv=ARGV)
11
+ new.run(argv)
12
+ end
13
+
14
+ #
15
+ #
16
+ #
17
+ def initialize
18
+ @force = false
19
+ @stdout = false
20
+ @static = false
21
+ end
22
+
23
+ #
24
+ #
25
+ #
26
+ def run(argv=ARGV)
27
+ cmd = nil
28
+ args = cli(argv,
29
+ '-d --debug' => lambda{ $DEBUG = true },
30
+ '-w --warn' => lambda{ $VERBOSE = true },
31
+ '-f --force' => lambda{ @force = true },
32
+ '-o --stdout' => lambda{ @stdout = true },
33
+ '-s --static' => lambda{ @static = true },
34
+ '-u --using' => lambda{ no_cmd!(cmd); cmd = :using },
35
+ '-a --adding' => lambda{ no_cmd!(cmd); cmd = :adding },
36
+ '-g --generate' => lambda{ no_cmd!(cmd); cmd = :generate },
37
+ '-h --help' => lambda{ no_cmd!(cmd); cmd = :help }
38
+ )
39
+ send(cmd || :show, *args)
40
+ rescue => error
41
+ raise error if $DEBUG
42
+ $stderr.puts "#{File.basename($0)} error: #{error}"
43
+ exit -1
44
+ end
45
+
46
+ #
47
+ # Show returns information from the `.index` file. Before doing so
48
+ # it always ensures the `.index` file is up to date. To suppress
49
+ # this update use the `-S/--static` option.
50
+ #
51
+ def show(*fields)
52
+ if @static
53
+ if Metadata.exists?
54
+ metadata = Metadata.open
55
+ puts metadata.about(*fields)
56
+ else
57
+ raise Error.exception(".index file not found", IOError)
58
+ end
59
+ else
60
+ Metadata.lock!(:force=>@force)
61
+ unless fields.empty?
62
+ metadata = Metadata.open
63
+ puts metadata.about(*fields)
64
+ end
65
+ end
66
+ end
67
+
68
+ #
69
+ def using(*sources)
70
+ raise Error.exception("no sources given") if sources.empty?
71
+ metadata = Metadata.lock(sources, :force=>true)
72
+ if @stdout
73
+ puts metadata.to_yaml
74
+ else
75
+ metadata.save!
76
+ end
77
+ end
78
+
79
+ #
80
+ def adding(*sources)
81
+ raise Error.exception("no sources given") if sources.empty?
82
+ metadata = Metadata.open
83
+ metadata = Metadata.lock((metadata.sources & sources), :force=>true)
84
+ if @stdout
85
+ puts metadata.to_yaml
86
+ else
87
+ metadata.save!
88
+ end
89
+ end
90
+
91
+ #
92
+ def generate(type, outfile=nil)
93
+ case type.downcase
94
+ when 'gemspec'
95
+ create_gemspec(outfile)
96
+ when 'ruby', 'index.rb', 'indexfile'
97
+ create_ruby(outfile)
98
+ when 'yaml', 'index.yml', 'index.yaml'
99
+ create_yaml(outfile)
100
+ else
101
+ raise Error.exception("unknown file type")
102
+ end
103
+ end
104
+
105
+ #
106
+ def help
107
+ puts <<-END
108
+ index [command-option] [options...] [arguments...]
109
+
110
+ (none) [fields...] update index and provide information from index
111
+ -u --using <sources...> create index using given information sources
112
+ -a --adding <sources...> update index appending additional information sources
113
+ -r --remove <sources...> update index removing given information sources
114
+ -g --generate <type> [fname] generate a file (gemspec, indexfile, metadata)
115
+ -h --help show this help message
116
+
117
+ -o --stdout output to console instead of saving to file
118
+ -f --force force protected file overwrite if file already exists or is up to date
119
+ -s --static keep index as is or generate static format if generator supports it
120
+ END
121
+ end
122
+
123
+ private
124
+
125
+ #
126
+ def create_ruby(outfile=nil)
127
+ require 'erb'
128
+
129
+ outfile = "Indexfile" unless outfile
130
+
131
+ if File.exist?(outfile) && !(@stdout or @force)
132
+ raise Error.exception("#{outfile} file already exists", IOError)
133
+ end
134
+
135
+ template_dir = File.join(DATADIR, "r#{REVISION}")
136
+ template_file = File.join(template_dir, 'ruby.txt')
137
+
138
+ if Metadata.exists?
139
+ metadata = Metadata.open
140
+ else
141
+ metadata = Metadata.new
142
+ end
143
+
144
+ # this is a little weak, but...
145
+ if gemspec = Dir['{,pkg/}*.gemspec'].first
146
+ metadata.import_gemspec(gemspec)
147
+ end
148
+
149
+ template = ERB.new(File.read(template_file))
150
+ result = template.result(Form.new(metadata).get_binding)
151
+
152
+ if @stdout
153
+ puts result
154
+ else
155
+ File.open(outfile, 'w') do |f|
156
+ f << result
157
+ end
158
+ end
159
+ end
160
+
161
+ #
162
+ def create_yaml(outfile)
163
+ require 'erb'
164
+
165
+ outfile = "Index.yml" unless outfile
166
+
167
+ if File.exist?(outfile) && !(@stdout or @force)
168
+ raise Error.exception("#{outfile} file already exists", IOError)
169
+ end
170
+
171
+ template_dir = File.join(DATADIR, "r#{REVISION}")
172
+ template_file = File.join(template_dir, 'yaml.txt')
173
+
174
+ if Metadata.exists?
175
+ metadata = Metadata.open
176
+ else
177
+ metadata = Metadata.new
178
+ end
179
+
180
+ # this is a little weak, but...
181
+ if gemspec = Dir['{,pkg/}*.gemspec'].first
182
+ metadata.import_gemspec(gemspec)
183
+ end
184
+
185
+ template = ERB.new(File.read(template_file))
186
+ result = template.result(Form.new(metadata).get_binding)
187
+
188
+ if @stdout
189
+ puts result
190
+ else
191
+ File.open(outfile, 'w') do |f|
192
+ f << result
193
+ end
194
+ end
195
+ end
196
+
197
+ #
198
+ # Create a .gemspec file for use with indexer. Or a static one if `--static` option is used.
199
+ #
200
+ def create_gemspec(file=nil)
201
+ if file
202
+ if File.extname(file) != '.gemspec'
203
+ warn "gemspec file without .gemspec extension"
204
+ end
205
+ else
206
+ # TODO: look for pre-existent gemspec, but to do that right we should get
207
+ # the name from the .index file if it eixts.
208
+ file = Dir['{,*,pkg/*}.gemspec'].first || '.gemspec'
209
+ end
210
+
211
+ #lib_file = File.join(DIR, "v#{which}", "gemspec.rb")
212
+
213
+ if file && File.exist?(file) && !@force && !@stdout
214
+ raise Error.exception("`#{file}' already exists, use -f/--force to overwrite.")
215
+ end
216
+
217
+ text = GemspecExporter.source_code + "\nIndexer::GemspecExporter.gemspec"
218
+
219
+ if @static
220
+ spec = eval(text, CleanBinding.new, file)
221
+ text = spec.to_yaml
222
+ end
223
+
224
+ if @stdout
225
+ puts text
226
+ else
227
+ File.open(file, 'w') do |f|
228
+ f << text
229
+ end
230
+ end
231
+ end
232
+
233
+ #
234
+ def no_cmd!(cmd)
235
+ raise Error.exception("more than one command flag") if cmd
236
+ end
237
+
238
+ # Helper class for generating template.
239
+ #
240
+ class Form
241
+ def initialize(metadata)
242
+ @metadata = metadata
243
+ end
244
+ def method_missing(s, *a, &b)
245
+ @metadata.public_send(s, *a, &b) || '<fill-out #{s}>'
246
+ end
247
+ def get_binding; binding; end
248
+ end
249
+
250
+ #
251
+ #
252
+ module CleanBinding
253
+ def self.new
254
+ binding
255
+ end
256
+ end
257
+
258
+ end
259
+
260
+ end