ore-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.document +4 -0
  2. data/.rspec +1 -0
  3. data/.yardopts +1 -0
  4. data/ChangeLog.md +17 -0
  5. data/GemspecYML.md +284 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +68 -0
  8. data/Rakefile +25 -0
  9. data/gemspec.yml +18 -0
  10. data/lib/ore.rb +3 -0
  11. data/lib/ore/checks.rb +88 -0
  12. data/lib/ore/defaults.rb +140 -0
  13. data/lib/ore/dependency.rb +65 -0
  14. data/lib/ore/document_file.rb +118 -0
  15. data/lib/ore/exceptions.rb +3 -0
  16. data/lib/ore/exceptions/exception.rb +4 -0
  17. data/lib/ore/exceptions/invalid_metadata.rb +6 -0
  18. data/lib/ore/exceptions/project_not_found.rb +6 -0
  19. data/lib/ore/naming.rb +113 -0
  20. data/lib/ore/paths.rb +146 -0
  21. data/lib/ore/project.rb +599 -0
  22. data/lib/ore/settings.rb +274 -0
  23. data/lib/ore/specification.rb +29 -0
  24. data/lib/ore/versions.rb +3 -0
  25. data/lib/ore/versions/exceptions.rb +1 -0
  26. data/lib/ore/versions/exceptions/invalid_version.rb +8 -0
  27. data/lib/ore/versions/version.rb +75 -0
  28. data/lib/ore/versions/version_constant.rb +126 -0
  29. data/lib/ore/versions/version_file.rb +66 -0
  30. data/lib/rubygems_plugin.rb +40 -0
  31. data/ore-core.gemspec +6 -0
  32. data/spec/dependency_spec.rb +36 -0
  33. data/spec/document_file_spec.rb +29 -0
  34. data/spec/helpers/files.rb +7 -0
  35. data/spec/helpers/files/.document +5 -0
  36. data/spec/helpers/files/VERSION +1 -0
  37. data/spec/helpers/files/VERSION.yml +5 -0
  38. data/spec/helpers/projects.rb +13 -0
  39. data/spec/helpers/projects/dm-is-plugin/Gemfile +3 -0
  40. data/spec/helpers/projects/dm-is-plugin/VERSION +1 -0
  41. data/spec/helpers/projects/dm-is-plugin/dm-is-plugin.gemspec +10 -0
  42. data/spec/helpers/projects/dm-is-plugin/gemspec.yml +9 -0
  43. data/spec/helpers/projects/dm-is-plugin/lib/dm-is-plugin.rb +4 -0
  44. data/spec/helpers/projects/dm-is-plugin/lib/dm-is-plugin/is/plugin.rb +6 -0
  45. data/spec/helpers/projects/explicit/gemspec.yml +19 -0
  46. data/spec/helpers/projects/explicit/lib/explicit/version.rb +15 -0
  47. data/spec/helpers/projects/ffi-binding/gemspec.yml +11 -0
  48. data/spec/helpers/projects/ffi-binding/lib/ffi/binding/version.rb +5 -0
  49. data/spec/helpers/projects/jewelery/VERSION +1 -0
  50. data/spec/helpers/projects/jewelery/bin/jewelery +3 -0
  51. data/spec/helpers/projects/jewelery/gemspec.yml +6 -0
  52. data/spec/helpers/projects/jewelery/jewelery.gemspec +10 -0
  53. data/spec/helpers/projects/jewelery/lib/jewelery.rb +4 -0
  54. data/spec/helpers/projects/jewelery/lib/jewelery/rubies.rb +4 -0
  55. data/spec/helpers/projects/minimal/gemspec.yml +4 -0
  56. data/spec/helpers/projects/minimal/lib/minimal.rb +2 -0
  57. data/spec/naming_spec.rb +56 -0
  58. data/spec/projects/dm_plugin_project_spec.rb +29 -0
  59. data/spec/projects/explicit_project_spec.rb +37 -0
  60. data/spec/projects/ffi_binding_project_spec.rb +25 -0
  61. data/spec/projects/jeweler_project_spec.rb +17 -0
  62. data/spec/projects/minimal_project_spec.rb +17 -0
  63. data/spec/projects/project_examples.rb +40 -0
  64. data/spec/spec_helper.rb +4 -0
  65. data/spec/versions/version_file_spec.rb +28 -0
  66. data/spec/versions/version_spec.rb +53 -0
  67. metadata +170 -0
@@ -0,0 +1,146 @@
1
+ require 'ore/naming'
2
+
3
+ module Ore
4
+ #
5
+ # A mixin for {Project} which provides methods for working with paths.
6
+ #
7
+ module Paths
8
+ include Naming
9
+
10
+ #
11
+ # Builds a path relative to the project.
12
+ #
13
+ # @param [Array] names
14
+ # The directory names of the path.
15
+ #
16
+ # @return [Pathname]
17
+ # The new path.
18
+ #
19
+ def path(*names)
20
+ @root.join(*names)
21
+ end
22
+
23
+ #
24
+ # The `bin/` directory of the project.
25
+ #
26
+ # @return [Pathname]
27
+ # The path to the `bin/` directory.
28
+ #
29
+ def bin_dir
30
+ @root.join(@@lib_dir)
31
+ end
32
+
33
+ #
34
+ # The `lib/` directory of the project.
35
+ #
36
+ # @return [Pathname]
37
+ # The path to the `lib/` directory.
38
+ #
39
+ def lib_dir
40
+ @root.join(@@lib_dir)
41
+ end
42
+
43
+ #
44
+ # The `pkg/` directory of the project.
45
+ #
46
+ # @return [Pathname]
47
+ # The path to the `pkg/` directory.
48
+ #
49
+ def pkg_dir
50
+ @root.join(@@pkg_dir)
51
+ end
52
+
53
+ #
54
+ # Builds a path relative to the `lib/` directory.
55
+ #
56
+ # @param [Array] names
57
+ # The directory names of the path.
58
+ #
59
+ # @return [Pathname]
60
+ # The new path.
61
+ #
62
+ def lib_path(*names)
63
+ path(@@lib_dir,*names)
64
+ end
65
+
66
+ #
67
+ # Builds a relative path into the `pkg/` directory for the `.gem` file.
68
+ #
69
+ # @return [String]
70
+ # The path of a `.gem` file for the project.
71
+ #
72
+ def pkg_file
73
+ File.join(@@pkg_dir,"#{@name}-#{@version}.gem")
74
+ end
75
+
76
+ #
77
+ # Determines if a directory exists within the project.
78
+ #
79
+ # @param [String] path
80
+ # The path of the directory, relative to the project.
81
+ #
82
+ # @return [Boolean]
83
+ # Specifies whether the directory exists in the project.
84
+ #
85
+ def directory?(path)
86
+ @root.join(path).directory?
87
+ end
88
+
89
+ #
90
+ # Determines if a file exists within the project.
91
+ #
92
+ # @param [String] path
93
+ # The path of the file, relative to the project.
94
+ #
95
+ # @return [Boolean]
96
+ # Specifies whether the file exists in the project.
97
+ #
98
+ def file?(path)
99
+ @project_files.include?(path)
100
+ end
101
+
102
+ #
103
+ # Determines if a directory exists within the `lib/` directory of the
104
+ # project.
105
+ #
106
+ # @return [Boolean]
107
+ # Specifies that the directory exists within the `lib/` directory.
108
+ #
109
+ def lib_directory?(path)
110
+ directory?(File.join(@@lib_dir,path))
111
+ end
112
+
113
+ #
114
+ # Determines if a file exists within the `lib/` directory of the
115
+ # project.
116
+ #
117
+ # @return [Boolean]
118
+ # Specifies that the file exists within the `lib/` directory.
119
+ #
120
+ def lib_file?(path)
121
+ file?(File.join(@@lib_dir,path))
122
+ end
123
+
124
+ #
125
+ # Finds paths within the project that match a glob pattern.
126
+ #
127
+ # @param [String] pattern
128
+ # The glob pattern.
129
+ #
130
+ # @yield [path]
131
+ # The given block will be passed matching paths.
132
+ #
133
+ # @yieldparam [String] path
134
+ # A path relative to the root directory of the project.
135
+ #
136
+ def glob(pattern)
137
+ within do
138
+ Dir.glob(pattern) do |path|
139
+ if (@project_files.include?(path) || File.directory?(path))
140
+ yield path
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,599 @@
1
+ require 'ore/exceptions/project_not_found'
2
+ require 'ore/exceptions/invalid_metadata'
3
+ require 'ore/naming'
4
+ require 'ore/paths'
5
+ require 'ore/checks'
6
+ require 'ore/defaults'
7
+ require 'ore/settings'
8
+ require 'ore/document_file'
9
+
10
+ require 'pathname'
11
+ require 'yaml'
12
+ require 'find'
13
+ require 'fileutils'
14
+
15
+ module Ore
16
+ #
17
+ # Combinds the metadata from the `gemspec.yml` file and the inferred
18
+ # information from the project directory.
19
+ #
20
+ class Project
21
+
22
+ include Naming
23
+ include Paths
24
+ include Checks
25
+ include Defaults
26
+ include Settings
27
+
28
+ # The project metadata file
29
+ @@metadata_file = 'gemspec.yml'
30
+
31
+ # The root directory of the project
32
+ attr_reader :root
33
+
34
+ # The SCM which the project is currently under
35
+ attr_reader :scm
36
+
37
+ # The files of the project
38
+ attr_reader :project_files
39
+
40
+ # The fully-qualified namespace of the project
41
+ attr_reader :namespace
42
+
43
+ # The infered namespace modules of the project
44
+ attr_reader :namespace_modules
45
+
46
+ # The directory contain the project code.
47
+ attr_reader :namespace_dir
48
+
49
+ # The name of the project
50
+ attr_reader :name
51
+
52
+ # The version of the project
53
+ attr_reader :version
54
+
55
+ # The project summary
56
+ attr_reader :summary
57
+
58
+ # The project description
59
+ attr_reader :description
60
+
61
+ # The licenses of the project
62
+ attr_reader :licenses
63
+
64
+ # The authors of the project
65
+ attr_reader :authors
66
+
67
+ # The homepage for the project
68
+ attr_reader :homepage
69
+
70
+ # The email contact for the project
71
+ attr_reader :email
72
+
73
+ # The build date for any project gems
74
+ attr_reader :date
75
+
76
+ # The parsed `.document` file
77
+ attr_reader :document
78
+
79
+ # The directories to search within the project when requiring files
80
+ attr_reader :require_paths
81
+
82
+ # The names of the executable scripts
83
+ attr_reader :executables
84
+
85
+ # The default executable
86
+ attr_reader :default_executable
87
+
88
+ # The documentation of the project
89
+ attr_reader :documentation
90
+
91
+ # Any extra files to include in the project documentation
92
+ attr_reader :extra_doc_files
93
+
94
+ # The files of the project
95
+ attr_reader :files
96
+
97
+ # The test files for the project
98
+ attr_reader :test_files
99
+
100
+ # Any external requirements needed by the project
101
+ attr_reader :requirements
102
+
103
+ # The version of Ruby required by the project
104
+ attr_reader :required_ruby_version
105
+
106
+ # The version of RubyGems required by the project
107
+ attr_reader :required_rubygems_version
108
+
109
+ # The dependencies of the project
110
+ attr_reader :dependencies
111
+
112
+ # The runtime-dependencies of the project
113
+ attr_reader :runtime_dependencies
114
+
115
+ # The development-dependencies of the project
116
+ attr_reader :development_dependencies
117
+
118
+ # The post-installation message
119
+ attr_reader :post_install_message
120
+
121
+ #
122
+ # Creates a new {Project}.
123
+ #
124
+ # @param [String] root
125
+ # The root directory of the project.
126
+ #
127
+ def initialize(root)
128
+ @root = Pathname.new(root).expand_path
129
+
130
+ unless @root.directory?
131
+ raise(ProjectNotFound,"#{@root} is not a directory")
132
+ end
133
+
134
+ infer_scm!
135
+ infer_project_files!
136
+
137
+ metadata_file = @root.join(@@metadata_file)
138
+
139
+ unless metadata_file.file?
140
+ raise(ProjectNotFound,"#{@root} does not contain #{@@metadata_file}")
141
+ end
142
+
143
+ metadata = YAML.load_file(metadata_file)
144
+
145
+ unless metadata.kind_of?(Hash)
146
+ raise(InvalidMetadata,"#{metadata_file} did not contain valid metadata")
147
+ end
148
+
149
+ if metadata['name']
150
+ @name = metadata['name'].to_s
151
+ else
152
+ default_name!
153
+ end
154
+
155
+ # infer the namespace from the project name
156
+ infer_namespace!
157
+
158
+ if metadata['version']
159
+ set_version! metadata['version']
160
+ else
161
+ default_version!
162
+ end
163
+
164
+ @summary = (metadata['summary'] || metadata['description'])
165
+ @description = (metadata['description'] || metadata['summary'])
166
+
167
+ @licenses = []
168
+
169
+ if metadata['license']
170
+ set_license!(metadata['license'])
171
+ end
172
+
173
+ @authors = []
174
+
175
+ if metadata['authors']
176
+ set_authors! metadata['authors']
177
+ end
178
+
179
+ @homepage = metadata['homepage']
180
+ @email = metadata['email']
181
+
182
+ if metadata['date']
183
+ set_date! metadata['date']
184
+ else
185
+ default_date!
186
+ end
187
+
188
+ @document = DocumentFile.find(self)
189
+
190
+ @require_paths = []
191
+
192
+ if metadata['require_paths']
193
+ set_require_paths! metadata['require_paths']
194
+ else
195
+ default_require_paths!
196
+ end
197
+
198
+ @executables = []
199
+
200
+ if metadata['executables']
201
+ set_executables! metadata['executables']
202
+ else
203
+ default_executables!
204
+ end
205
+
206
+ @default_executable = nil
207
+
208
+ if metadata['default_executable']
209
+ set_default_executable! metadata['default_executable']
210
+ else
211
+ default_executable!
212
+ end
213
+
214
+ if metadata['has_yard']
215
+ @documentation = :yard
216
+ elsif metadata.has_key?('has_rdoc')
217
+ @documentation = if metadata['has_rdoc']
218
+ :rdoc
219
+ end
220
+ else
221
+ default_documentation!
222
+ end
223
+
224
+ @extra_doc_files = []
225
+
226
+ if metadata['extra_doc_files']
227
+ set_extra_doc_files! metadata['extra_doc_files']
228
+ else
229
+ default_extra_doc_files!
230
+ end
231
+
232
+ @files = []
233
+
234
+ if metadata['files']
235
+ set_files! metadata['files']
236
+ else
237
+ default_files!
238
+ end
239
+
240
+ @test_files = []
241
+
242
+ if metadata['test_files']
243
+ set_test_files! metadata['test_files']
244
+ else
245
+ default_test_files!
246
+ end
247
+
248
+ if metadata['post_install_message']
249
+ set_post_install_message! metadata['post_install_message']
250
+ end
251
+
252
+ @requirements = []
253
+
254
+ if metadata['requirements']
255
+ set_requirements! metadata['requirements']
256
+ end
257
+
258
+ if metadata['required_ruby_version']
259
+ set_required_ruby_version! metadata['required_ruby_version']
260
+ end
261
+
262
+ if metadata['required_rubygems_version']
263
+ set_required_rubygems_version! metadata['required_rubygems_version']
264
+ else
265
+ default_required_rubygems_version!
266
+ end
267
+
268
+ @dependencies = []
269
+
270
+ if metadata['dependencies']
271
+ set_dependencies! metadata['dependencies']
272
+ end
273
+
274
+ @runtime_dependencies = []
275
+
276
+ if metadata['runtime_dependencies']
277
+ set_runtime_dependencies! metadata['runtime_dependencies']
278
+ end
279
+
280
+ @development_dependencies = []
281
+
282
+ if metadata['development_dependencies']
283
+ set_development_dependencies! metadata['development_dependencies']
284
+ end
285
+ end
286
+
287
+ #
288
+ # Finds the project metadata file and creates a new {Project} object.
289
+ #
290
+ # @param [String] dir (Dir.pwd)
291
+ # The directory to start searching upward from.
292
+ #
293
+ # @return [Project]
294
+ # The found project.
295
+ #
296
+ # @raise [ProjectNotFound]
297
+ # No project metadata file could be found.
298
+ #
299
+ def self.find(dir=Dir.pwd)
300
+ Pathname.new(dir).ascend do |root|
301
+ return self.new(root) if root.join(@@metadata_file).file?
302
+ end
303
+
304
+ raise(ProjectNotFound,"could not find #{@@metadata_file}")
305
+ end
306
+
307
+ #
308
+ # Executes code within the project.
309
+ #
310
+ # @param [String] sub_dir
311
+ # An optional sub-directory within the project to execute from.
312
+ #
313
+ # @yield []
314
+ # The given block will be called once the current working-directory
315
+ # has been switched. Once the block finishes executing, the current
316
+ # working-directory will be switched back.
317
+ #
318
+ # @see http://ruby-doc.org/core/classes/Dir.html#M002314
319
+ #
320
+ def within(sub_dir=nil,&block)
321
+ dir = if sub_dir
322
+ @root.join(sub_dir)
323
+ else
324
+ @root
325
+ end
326
+
327
+ Dir.chdir(dir,&block)
328
+ end
329
+
330
+ #
331
+ # The primary license of the project.
332
+ #
333
+ # @return [String, nil]
334
+ # The primary license for the project.
335
+ #
336
+ def license
337
+ @licenses.first
338
+ end
339
+
340
+ #
341
+ # Determines whether the project uses Bundler.
342
+ #
343
+ # @return [Boolean]
344
+ # Specifies whether the project uses Bundler.
345
+ #
346
+ def bundler?
347
+ file?('Gemfile')
348
+ end
349
+
350
+ #
351
+ # Determines whether the project has been bundled using Bundler.
352
+ #
353
+ # @return [Boolean]
354
+ # Specifies whether the project has been bundled.
355
+ #
356
+ def bundled?
357
+ file?('Gemfile.lock')
358
+ end
359
+
360
+ #
361
+ # Determines if the project contains RDoc documentation.
362
+ #
363
+ # @return [Boolean]
364
+ # Specifies whether the project has RDoc documentation.
365
+ #
366
+ def has_rdoc
367
+ @documentation == :rdoc
368
+ end
369
+
370
+ #
371
+ # Determines if the project contains YARD documentation.
372
+ #
373
+ # @return [Boolean]
374
+ # Specifies whether the project has YARD documentation.
375
+ #
376
+ def has_yard
377
+ @documentation == :yard
378
+ end
379
+
380
+ #
381
+ # Populates a Gem Specification using the metadata of the project.
382
+ #
383
+ # @yield [gemspec]
384
+ # The given block will be passed the populated Gem Specification
385
+ # object.
386
+ #
387
+ # @yieldparam [Gem::Specification] gemspec
388
+ # The newly created Gem Specification.
389
+ #
390
+ # @return [Gem::Specification]
391
+ # The Gem Specification.
392
+ #
393
+ # @see http://rubygems.rubyforge.org/rdoc/Gem/Specification.html
394
+ #
395
+ def to_gemspec
396
+ Gem::Specification.new do |gemspec|
397
+ gemspec.name = @name.to_s
398
+ gemspec.version = @version.to_s
399
+ gemspec.summary = @summary.to_s
400
+ gemspec.description = @description.to_s
401
+ gemspec.licenses = @licenses
402
+ gemspec.authors = @authors
403
+ gemspec.homepage = @homepage
404
+ gemspec.email = @email
405
+ gemspec.date = @date
406
+
407
+ @require_paths.each do |path|
408
+ unless gemspec.require_paths.include?(path)
409
+ gemspec.require_paths << path
410
+ end
411
+ end
412
+
413
+ gemspec.executables = @executables
414
+ gemspec.default_executable = @default_executable
415
+
416
+ gemspec.has_rdoc = if has_yard
417
+ 'yard'
418
+ elsif has_rdoc
419
+ true
420
+ end
421
+
422
+ gemspec.extra_rdoc_files = @extra_doc_files
423
+ gemspec.files = @files
424
+ gemspec.test_files = @test_files
425
+ gemspec.post_install_message = @post_install_message
426
+
427
+ gemspec.requirements = @requirements
428
+
429
+ if gemspec.respond_to?(:required_ruby_version=)
430
+ gemspec.required_ruby_version = @required_ruby_version
431
+ end
432
+
433
+ if gemspec.respond_to?(:required_rubygems_version=)
434
+ gemspec.required_rubygems_version = @required_rubygems_version
435
+ end
436
+
437
+ @dependencies.each do |dep|
438
+ gemspec.add_dependency(dep.name,*dep.versions)
439
+ end
440
+
441
+ if gemspec.respond_to?(:add_runtime_dependency)
442
+ @runtime_dependencies.each do |dep|
443
+ gemspec.add_runtime_dependency(dep.name,*dep.versions)
444
+ end
445
+ else
446
+ @runtime_dependencies.each do |dep|
447
+ gemspec.add_dependency(dep.name,*dep.versions)
448
+ end
449
+ end
450
+
451
+ if gemspec.respond_to?(:add_development_dependency)
452
+ @development_dependencies.each do |dep|
453
+ gemspec.add_development_dependency(dep.name,*dep.versions)
454
+ end
455
+ else
456
+ @development_dependencies.each do |dep|
457
+ gemspec.add_dependency(dep.name,*dep.versions)
458
+ end
459
+ end
460
+
461
+ # legacy information
462
+ if gemspec.respond_to?(:rubyforge_project=)
463
+ gemspec.rubyforge_project = gemspec.name
464
+ end
465
+
466
+ yield gemspec if block_given?
467
+ end
468
+ end
469
+
470
+ #
471
+ # Builds a gem for the project.
472
+ #
473
+ # @return [Pathname]
474
+ # The path to the built gem file within the `pkg/` directory.
475
+ #
476
+ def build!
477
+ pkg_dir = @root.join(@@pkg_dir)
478
+ FileUtils.mkdir_p(pkg_dir)
479
+
480
+ gem_file = Gem::Builder.new(self.to_gemspec).build
481
+ pkg_path = @root.join(pkg_file)
482
+
483
+ FileUtils.mv(gem_file,pkg_path)
484
+ return pkg_path
485
+ end
486
+
487
+ protected
488
+
489
+ #
490
+ # Prints multiple warning messages.
491
+ #
492
+ # @param [Array] messages
493
+ # The messages to print.
494
+ #
495
+ def warn(*messages)
496
+ messages.each { |mesg| STDERR.puts("WARNING: #{mesg}") }
497
+ end
498
+
499
+ #
500
+ # Infers the Source Code Management used by the project.
501
+ #
502
+ def infer_scm!
503
+ if @root.join('.git').directory?
504
+ @scm = :git
505
+ else
506
+ @scm = nil
507
+ end
508
+ end
509
+
510
+ #
511
+ # Infers the project files.
512
+ #
513
+ def infer_project_files!
514
+ @project_files = Set[]
515
+
516
+ filter_path = lambda { |path|
517
+ check_readable(path) { |file| @project_files << file }
518
+ }
519
+
520
+ within do
521
+ case @scm
522
+ when :git
523
+ `git ls-files -z`.split("\0").each(&filter_path)
524
+ else
525
+ within { Dir.glob('{**/}*',&filter_path) }
526
+ end
527
+ end
528
+ end
529
+
530
+ #
531
+ # Infers the namespace of the project based on the project name.
532
+ #
533
+ def infer_namespace!
534
+ @namespace_modules = modules_of(@name)
535
+ @namespace = namespace_of(@name)
536
+
537
+ dir = namespace_path_of(@name)
538
+
539
+ @namespace_dir = if lib_directory?(dir)
540
+ dir
541
+ elsif lib_directory?(@name)
542
+ @name
543
+ end
544
+ end
545
+
546
+ #
547
+ # Adds a require-path to the project.
548
+ #
549
+ # @param [String] path
550
+ # A directory path relative to the project.
551
+ #
552
+ def add_require_path(path)
553
+ check_directory(path) { |dir| @require_paths << dir }
554
+ end
555
+
556
+ #
557
+ # Adds an executable to the project.
558
+ #
559
+ # @param [String] name
560
+ # The name of the executable.
561
+ #
562
+ def add_executable(name)
563
+ path = File.join(@@bin_dir,name)
564
+
565
+ check_executable(path) { |exe| @executables << exe }
566
+ end
567
+
568
+ #
569
+ # Adds an extra documentation file to the project.
570
+ #
571
+ # @param [String] path
572
+ # The path to the file, relative to the project.
573
+ #
574
+ def add_extra_doc_file(path)
575
+ check_file(path) { |file| @extra_doc_files << file }
576
+ end
577
+
578
+ #
579
+ # Adds a file to the project.
580
+ #
581
+ # @param [String] path
582
+ # The path to the file, relative to the project.
583
+ #
584
+ def add_file(path)
585
+ check_file(path) { |file| @files << file }
586
+ end
587
+
588
+ #
589
+ # Adds a testing-file to the project.
590
+ #
591
+ # @param [String] path
592
+ # The path to the testing-file, relative to the project.
593
+ #
594
+ def add_test_file(path)
595
+ check_file(path) { |file| @test_files << file }
596
+ end
597
+
598
+ end
599
+ end