technicalpickles/jeweler

View on GitHub
lib/jeweler/gemspec_helper.rb

Summary

Maintainability
A
0 mins
Test Coverage
class Jeweler
  class GemSpecHelper
    attr_accessor :spec, :base_dir

    def initialize(spec, base_dir = nil)
      self.spec = spec
      self.base_dir = base_dir || ''

      yield spec if block_given?
    end

    def valid?
      parse
      true
    rescue
      false
    end

    def write
      File.open(path, 'w') do |f|
        f.write to_ruby
      end
    end

    def to_ruby
      normalize_files(:files)
      normalize_files(:extra_rdoc_files)

      gemspec_ruby = @spec.to_ruby
      gemspec_ruby = prettyify_array(gemspec_ruby, :files)
      gemspec_ruby = prettyify_array(gemspec_ruby, :extra_rdoc_files)
      gemspec_ruby = <<-END
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in #{Rake.application.rakefile}, and run 'rake gemspec'
#{gemspec_ruby}
        END
    end

    def path
      denormalized_path = File.join(@base_dir, "#{@spec.name}.gemspec")
      absolute_path = File.expand_path(denormalized_path)
      absolute_path.gsub(Dir.getwd + File::SEPARATOR, '')
    end

    PARSE_SAFE = (RUBY_VERSION >= '2.3') ? 1 : 3

    def parse
      data = to_ruby
      parsed_gemspec = nil
      Thread.new { parsed_gemspec = eval("$SAFE = #{PARSE_SAFE}\n#{data}", binding, path) }.join
      # Need to reset $SAFE to 0 as it is process global since ruby 2.6
      $SAFE = 0 if $SAFE == 1
      parsed_gemspec
    end

    def normalize_files(array_attribute)
      array = @spec.send(array_attribute)
      # only keep files, no directories, and sort
      array = array.select do |path|
        File.file? File.join(@base_dir, path)
      end.sort

      @spec.send("#{array_attribute}=", array)
    end

    # Adds extra space when outputting an array. This helps create better version control diffs, because otherwise it is all on the same line.
    def prettyify_array(gemspec_ruby, array_name)
      gemspec_ruby.gsub(/s\.#{array_name.to_s} = \[.+?\]/) do |match|
        leadin, files = match[0..-2].split('[')

        leadin + "[\n    #{files.gsub(%(", "), %(",\n    "))}\n  ]"
      end
    end

    def gem_path
      File.join(@base_dir, 'pkg', parse.file_name)
    end

    def update_version(version)
      @spec.version = version.to_s
    end

    # Checks whether it uses the version helper or the users defined version.
    def has_version?
      !@spec.version.nil?
    end
  end
end