require 'rubygems' class Hbc::Source::PathBase # derived classes must define method self.me? def self.path_for_query(query) path_string = "#{query}" path_string.concat('.rb') unless path_string.match(%r{\.rb\Z}i) Pathname.new(path_string) end attr_reader :path def initialize(path) @path = Pathname(path).expand_path end def load raise Hbc::CaskError.new "File '#{path}' does not exist" unless path.exist? raise Hbc::CaskError.new "File '#{path}' is not readable" unless path.readable? raise Hbc::CaskError.new "File '#{path}' is not a plain file" unless path.file? begin # transitional hack: convert first lines of the new form # # cask :v1 => 'google-chrome' do # # to the old form # # class GoogleChrome < Hbc (class GoogleChrome < Cask) # # limitation: does not support Ruby extended quoting such as %Q{} # # todo: in the future, this can be pared down to an "eval" # read Cask cask_contents = File.open(path, 'rb') do |handle| contents = handle.read if defined?(Encoding) contents.force_encoding('UTF-8') else contents end end # munge text cask_contents.sub!(%r{\A(\s*\#[^\n]*\n)+}, ''); if %r{\A\s*cask\s+:v([\d_]+)(test)?\s+=>\s+([\'\"])(\S+?)\3(?:\s*,\s*|\s+)do\s*\n}.match(cask_contents) dsl_version_string = $1 is_test = ! $2.nil? header_token = $4 dsl_version = Gem::Version.new(dsl_version_string.gsub('_','.')) superclass_name = is_test ? 'Hbc::TestCask' : 'Hbc::Cask' cask_contents.sub!(%r{\A[^\n]+\n}, "class #{cask_class_name} < #{superclass_name}\n") # todo the minimum DSL version should be defined globally elsewhere minimum_dsl_version = Gem::Version.new('1.0') unless dsl_version >= minimum_dsl_version raise Hbc::CaskInvalidError.new(cask_token, "Bad header line: 'v#{dsl_version_string}' is less than required minimum version '#{minimum_dsl_version}'") end if header_token != cask_token raise Hbc::CaskInvalidError.new(cask_token, "Bad header line: '#{header_token}' does not match file name") end else raise Hbc::CaskInvalidError.new(cask_token, "Bad header line: parse failed") end # simulate "require" begin Object.const_get(cask_class_name) rescue NameError eval(cask_contents, TOPLEVEL_BINDING) end rescue Hbc::CaskError, StandardError, ScriptError => e # bug: e.message.concat doesn't work with Hbc::CaskError exceptions e.message.concat(" while loading '#{path}'") raise e end begin Object.const_get(cask_class_name).new(path) rescue Hbc::CaskError, StandardError, ScriptError => e # bug: e.message.concat doesn't work with Hbc::CaskError exceptions e.message.concat(" while instantiating '#{cask_class_name}' from '#{path}'") raise e end end def cask_token path.basename.to_s.sub(/\.rb/, '') end def cask_class_name # todo removeme: prepending KlassPrefix is transitional as we move away from representing Casks as classes 'KlassPrefix'.concat cask_token.split('-').map(&:capitalize).join end def to_s # stringify to fully-resolved location path.to_s end end