1

I've got some code to add methods to a module from simple definitions for talking to remote resources via a wrapper class around a REST client.

def service_function(function_name, method, uri, parameters)
  class_eval <<-RUBY
    def #{function_name}(params)
      if !(#{function_name}_required_params - params.keys).empty? || \
           !(params.keys - #{function_name}_params).empty?
        raise Errors::InvalidParameters.new(service_name, __method__,
                                            params.keys, #{function_name}_params)
      end
      WebServices::ServiceRequest.perform(self.domain, #{uri}, #{method}, params)
    end

    def #{function_name}_params
      #{function_name}_required_params + #{function_name}_optional_params
    end

    def #{function_name}_required_params
      #{parameters}.select { |param,req| req }.keys
    end

    def #{function_name}_optional_params
      #{parameters}.select { |param,req| !req }.keys
    end
  RUBY
end

Before I can even run the code, just requiring the gem I'm building into IRB spits out this error:

1.9.2p320 :001 > require 'web-services'
SyntaxError: (eval):7: unknown regexp options - rt

The offending line is:

WebServices::ServiceRequest.perform(self.domain, #{uri}, #{method}, params)

Removing the "#{uri}" argument fixes it, even leaving in the "#{method}" argument. Does anyone out there have a clue as to why this might be? I'm about at my wit's end.

1 Answers1

1

You have a url that looks something like /something/rt and that will look like a regex literal in here:

WebServices::ServiceRequest.perform(self.domain, #{uri}, #{method}, params)

You need to escape and quote #{uri} so that it looks like a string inside the heredoc, that way class_eval will see perform(..., '/something/rt', ...) and be happy. You might have similar issues with #{method}.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • The thing is I'm not passing anything in yet, this in just on require. When I remove #{uri} it works perfectly. *EDIT* Nevermind, I found a stray line of code from earlier testing on it that was being executed during the require step. I feel a bit silly now. Thanks for the reply. =) – user1034016 Jul 23 '12 at 06:03
  • For posterity's and google's sake, the solution was to replace #{uri} with "#{uri}". – user1034016 Jul 23 '12 at 06:18
  • @user1034016: That should be safe but the truly paranoid would want to make sure that `uri` didn't have any double quotes or do something like `"#{uri.inspect}"` to get them escaped. – mu is too short Jul 23 '12 at 06:36