Question

There is a common trick to re-use a string within a pod spec:

  s.version = '0.0.2'
  s.source = { :git => ..., :tag => s.version }

By reusing the s.version string after it's assigned, I don't have to remember to change two fields when I update my podspec.

But, what I'd really like to do is tag my code with "v0.0.2", not "0.0.2". So I tried to just create a new string by prepending a 'v' to the version:

  s.source = { :git => ..., :tag => 'v' +  s.version }

However, that bombs the pod command.

I recall seeing a trick while searching for something else a while ago that showed how to inject Ruby code into a spec, but I cannot find it now, and even if I could not sure it addressed what I'm trying to do.

So, my question is, is this even possible, and if so, how do I accomplish it?

Was it helpful?

Solution

You are missing a .to_s call. I created a sample podspec to reproduce your issue. Indeed, the:

s.source = { :git => ..., :tag => 'v' +  s.version }

does not pass validation using lint and I got lots of errors. However, I added the to_s call and it worked for me and lint started fetching my v1.0.0 tag.

s.source = { :git => ..., :tag => 'v' +  s.version.to_s }

Hope it helps.

OTHER TIPS

First I wanted to provide an alternative answer. Instead of using Ruby string concatenation

'v' + s.version.to_s

you could also have used Ruby string interpolation, which is what most people would use in this situation

"v#{s.version}"

In Ruby #{...} is like ${...} in shell scripts or Perl, the whole expression is replaced by the output of the code fragment (...), which can be a variable, a method call or any other piece of code. But this only works in in double quotes (again, just like in shell scripts or Perl).

Now regarding the comment that the OP @DavidH made in reply to the answer of @RaffAl:

I don't know Ruby at all. s.version is a string, but I have to turn it into a string to create a new string (see why I'm getting dizzy!).

Ruby is an extremely dynamic language, where everything is an object and almost everything is implemented as a method, even most of the operators. E.g. a = b + c in fact calls the method + (yes, that is a valid method name in Ruby) on b with the parameter c, so it's in fact the same as a = b.+(c).

When you write

s.version = '0.0.2'

it looks as if you are just assigning a value to a variable but what happens in fact is that a setter method is called, as this code is the same as:

s.version=('0.0.2')

And yes, the method is in fact named version= (certain operators are allowed in method names in Ruby). In Java the method would most likely be named setVersion(). Just because you pass a string to a setter doesn't mean that this string is also stored anywhere.

And when you call

x = s.version

you are in fact calling a getter method:

x = s.version()

In Java this method would be named getVersion(). And this getter doesn't return a string, it returns a Version object. So your initial code

'v' + s.version

In fact does this:

'v'.+(s.version)

But the problem is, the + method of the class String doesn't know how to append an object of class Version and that's why it fails.

All Ruby classes must inherit from another class and if they don't, they simply inherit from the class Object and this class defines a method to_s(), so any Ruby object knows to_s (parenthesis are always optional in Ruby, puts("Hello World") is the same as puts "Hello World"). If they don't override it, it prints the class name and an encoding of the object ID, but a lot of classes have overridden this method to return something more meaningful. The Version class returns the version as a string.

Okay, but why does string interpolation work then? Because unless the result of the expression in #{...} produces a string, Ruby will call to_s on that result to get one, that's why.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top