|
| 1 | +# encoding: utf-8 |
| 2 | + |
| 3 | +require 'yaml' |
| 4 | + |
| 5 | +module DotRuby |
| 6 | + |
| 7 | + # |
| 8 | + class GemSpec |
| 9 | + |
| 10 | + # For which revision of .ruby is this gemspec intended? |
| 11 | + REVISION = 0 unless defined?(REVISION) |
| 12 | + |
| 13 | + # |
| 14 | + PATTERNS = { |
| 15 | + :bin_files => 'bin/*', |
| 16 | + :lib_files => 'lib/{**/}*.rb', |
| 17 | + :ext_files => 'ext/{**/}extconf.rb', |
| 18 | + :doc_files => '*.{txt,rdoc,md,markdown,tt,textile}', |
| 19 | + :test_files => '{test/{**/}*_test.rb,spec/{**/}*_spec.rb}' |
| 20 | + } unless defined?(PATTERNS) |
| 21 | + |
| 22 | + # |
| 23 | + def self.instance |
| 24 | + new.to_gemspec |
| 25 | + end |
| 26 | + |
| 27 | + attr :metadata |
| 28 | + |
| 29 | + attr :manifest |
| 30 | + |
| 31 | + # |
| 32 | + def initialize |
| 33 | + @metadata = YAML.load_file('.ruby') |
| 34 | + @manifest = Dir.glob('manifest{,.txt}', File::FNM_CASEFOLD).first |
| 35 | + |
| 36 | + if @metadata['revision'].to_i != REVISION |
| 37 | + warn "You have the wrong revision. Trying anyway..." |
| 38 | + end |
| 39 | + end |
| 40 | + |
| 41 | + # |
| 42 | + def scm |
| 43 | + @scm ||= \ |
| 44 | + case |
| 45 | + when File.directory?('.git') |
| 46 | + :git |
| 47 | + end |
| 48 | + end |
| 49 | + |
| 50 | + # |
| 51 | + def files |
| 52 | + @files ||= \ |
| 53 | + #glob_files[patterns[:files]] |
| 54 | + case |
| 55 | + when manifest |
| 56 | + File.readlines(manifest). |
| 57 | + map{ |line| line.strip }. |
| 58 | + reject{ |line| line.empty? || line[0,1] == '#' } |
| 59 | + when scm == :git |
| 60 | + `git ls-files -z`.split("\0") |
| 61 | + else |
| 62 | + Dir.glob('{**/}{.*,*}') # TODO: be more specific using standard locations ? |
| 63 | + end.select{ |path| File.file?(path) } |
| 64 | + end |
| 65 | + |
| 66 | + # |
| 67 | + def glob_files(pattern) |
| 68 | + Dir.glob(pattern).select { |path| |
| 69 | + File.file?(path) && files.include?(path) |
| 70 | + } |
| 71 | + end |
| 72 | + |
| 73 | + # |
| 74 | + def patterns |
| 75 | + PATTERNS |
| 76 | + end |
| 77 | + |
| 78 | + # |
| 79 | + def executables |
| 80 | + @executables ||= \ |
| 81 | + glob_files(patterns[:bin_files]).map do |path| |
| 82 | + File.basename(path) |
| 83 | + end |
| 84 | + end |
| 85 | + |
| 86 | + def extensions |
| 87 | + @extensions ||= \ |
| 88 | + glob_files(patterns[:ext_files]).map do |path| |
| 89 | + File.basename(path) |
| 90 | + end |
| 91 | + end |
| 92 | + |
| 93 | + # |
| 94 | + def name |
| 95 | + metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') |
| 96 | + end |
| 97 | + |
| 98 | + # |
| 99 | + def to_gemspec |
| 100 | + Gem::Specification.new do |gemspec| |
| 101 | + gemspec.name = name |
| 102 | + gemspec.version = metadata['version'] |
| 103 | + gemspec.summary = metadata['summary'] |
| 104 | + gemspec.description = metadata['description'] |
| 105 | + |
| 106 | + metadata['authors'].each do |author| |
| 107 | + gemspec.authors << author['name'] |
| 108 | + |
| 109 | + if author.has_key?('email') |
| 110 | + if gemspec.email |
| 111 | + gemspec.email << author['email'] |
| 112 | + else |
| 113 | + gemspec.email = [author['email']] |
| 114 | + end |
| 115 | + end |
| 116 | + end |
| 117 | + |
| 118 | + gemspec.licenses = metadata['copyrights'].map{ |c| c['license'] }.compact |
| 119 | + |
| 120 | + metadata['requirements'].each do |req| |
| 121 | + name = req['name'] |
| 122 | + version = req['version'] |
| 123 | + groups = req['groups'] || [] |
| 124 | + |
| 125 | + case version |
| 126 | + when /^(.*?)\+$/ |
| 127 | + version = ">= #{$1}" |
| 128 | + when /^(.*?)\-$/ |
| 129 | + version = "< #{$1}" |
| 130 | + when /^(.*?)\~$/ |
| 131 | + version = "~> #{$1}" |
| 132 | + end |
| 133 | + |
| 134 | + if groups.empty? or groups.include?('runtime') |
| 135 | + # populate runtime dependencies |
| 136 | + if gemspec.respond_to?(:add_runtime_dependency) |
| 137 | + gemspec.add_runtime_dependency(name,*version) |
| 138 | + else |
| 139 | + gemspec.add_dependency(name,*version) |
| 140 | + end |
| 141 | + else |
| 142 | + # populate development dependencies |
| 143 | + if gemspec.respond_to?(:add_development_dependency) |
| 144 | + gemspec.add_development_dependency(name,*version) |
| 145 | + else |
| 146 | + gemspec.add_dependency(name,*version) |
| 147 | + end |
| 148 | + end |
| 149 | + end |
| 150 | + |
| 151 | + # convert external dependencies into a requirements |
| 152 | + if metadata['external_dependencies'] |
| 153 | + ##gemspec.requirements = [] unless metadata['external_dependencies'].empty? |
| 154 | + metadata['external_dependencies'].each do |req| |
| 155 | + gemspec.requirements << req.to_s |
| 156 | + end |
| 157 | + end |
| 158 | + |
| 159 | + # determine homepage from resources |
| 160 | + homepage = metadata['resources'].find{ |key, url| key =~ /^home/ } |
| 161 | + gemspec.homepage = homepage.last if homepage |
| 162 | + |
| 163 | + gemspec.require_paths = metadata['load_path'] || ['lib'] |
| 164 | + gemspec.post_install_message = metadata['install_message'] |
| 165 | + |
| 166 | + # RubyGems specific metadata |
| 167 | + gemspec.files = files |
| 168 | + gemspec.extensions = extensions |
| 169 | + gemspec.executables = executables |
| 170 | + |
| 171 | + if Gem::VERSION < '1.7.' |
| 172 | + gemspec.default_executable = gemspec.executables.first |
| 173 | + end |
| 174 | + |
| 175 | + gemspec.test_files = glob_files(patterns[:test_files]) |
| 176 | + |
| 177 | + unless gemspec.files.include?('.document') |
| 178 | + gemspec.extra_rdoc_files = glob_files(patterns[:doc_files]) |
| 179 | + end |
| 180 | + end |
| 181 | + end |
| 182 | + |
| 183 | + end #class GemSpec |
| 184 | + |
| 185 | +end |
| 186 | + |
| 187 | +DotRuby::GemSpec.instance |
0 commit comments