Search code examples
rubyrubygemsgemspecs

Calling a method inside a do block in ruby


I'm trying to include files from all git submodules in a gemspec file. The gemspec reads as following

require File.expand_path(File.dirname(__FILE__)) + '/lib/nameofgem.rb'
# Gets all files, from all submodules, and returns them
# as an array
def getSubmoduleFiles()
  files = []

  # get an array of submodule dirs by executing 'pwd' inside each submodule
  `git submodule --quiet foreach pwd`.split("\n").each do |submodule_path|

    gemRootDir = File.dirname(File.expand_path(__FILE__))

    # for each submodule, change working directory to that submodule
    Dir.chdir(submodule_path) do
      submodule_files = getSubmoduleFiles()
      # issue git ls-files in submodule's directory
      submodule_files + `git ls-files`.split("\n")

      puts "found:"
      puts submodule_files.to_s
      puts

      # prepend the submodule path to create absolute file paths
      submodule_files_fullpaths = submodule_files.map do |filename|
        "#{submodule_path}/#{filename}"
      end

      # remove leading path parts to get paths relative to the gem's root dir
      # (this assumes, that the gemspec resides in the gem's root dir)
      submodule_files_paths = submodule_files_fullpaths.map do |filename|
        filename.gsub "#{gemRootDir}/", ""
      end

      # add relative paths to gem.files
      files += submodule_files_paths
    end
  end

  return files
end

Gem::Specification.new do |s|
  s.name        = 'name'
  s.version     = "1.1.1"
  s.executables << 'exec'
  s.licenses    = ['LICENCE']
  s.summary     = "Does stuff"
  s.description = "Longer description of stuff"
  s.authors     = ["author"]
  s.email       = 'my@email'
  s.files       = `git ls-files -- lib/*`.split("\n")
  s.homepage    = 'https://example.com/'
  s.required_ruby_version = '>= 2.0.0'

  s.files += getSubmoduleFiles()
end

But in the do block, I get

Invalid gemspec in [nameofgem.gemspec]: undefined method `getSubmoduleFiles' for Gem::Specification:::Module

What am I doing wrong? Why can't a call the function from within the do block?


Solution

  • It seems that gemspec files do some weird stuff with scoping and namespacing (in the entire file, not just within the gemspec block itself), but after banging my head against my desk for 15 minutes and downing yet another beer to dull the existential torment induced by my inability to call a function in a gemspec, I figured out a reasonably clean solution: just stick self. in front of the function name in both the definition and invocation, like so:

    def self.foo
      puts 'It works :)'
    end
    
    Gem::Specification.new do |s|
      # ...
      self.foo  # should print 'It works :)' instead of erroring out
      # ...
    end
    

    Why this is necessary, and why nobody else seems to have asked or answered this question anywhere on the World Wide Web, I haven't the faintest idea, but here we go.