

Show HN: NSString + Ruby - thingsdoer
https://github.com/zdavison/NSString-Ruby

======
dennis_vartan
Like! Much as I love ObjC, reducing verbosity via better syntax can go a long
way to making code more readable.

For example, I ended up putting together some defines like this after building
a bunch of UI programmatically.

    
    
      #define RGB(r, g, b)     [NSColor colorWithDeviceRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
      #define RGBA(r, g, b, a) [NSColor colorWithDeviceRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)]
    

RGB(255, 104, 0) may be a bit too C-ish, but it sure beats the long form. Have
similar GRAY(x) and GRAYA(x) defines for producing grayscale colors.

Definitely interested to see more projects along these lines.

~~~
bennyg
I wrote a utility class with idiomatic Obj-C color methods like the one you
mentioned and more. I hate to plug it, but I'm fairly proud of it. It also
generates color schemes when you throw a UIColor object at it, and includes
100 different UIColor generics like [UIColor seafoamColor].

[https://github.com/bennyguitar/Colours-for-
iOS](https://github.com/bennyguitar/Colours-for-iOS)

~~~
reginaldjcooper
Why on Earth would you hate to plug this? I could definitely see someone using
this and being thankful they don't have to do it themselves. Hell, I'd use it
if I hadn't already done my own category.

Suggestions: you might want to allow for three-digit hex strings and
eight/four digit hex strings with alpha, I found that convenient in mine. And
in the documentation it would be way cool if you made the names of the colors
self-referential.

Nits: I would have made all the system color methods like "systemThingColor",
capitalized RGB and HSB, and made "RGBDictionary" return @{@"red": ...} (and
made static NSStrings for the keys so nobody needs to go to the .m file to see
what will happen). Obviously I am a pedant and I live right on the edge of the
80 character limit; of these I'd only suggest making static dictionary keys as
an actually desirable change.

Nice work, you shouldn't be ashamed to share it at all.

------
jakobe
One thing that irks me is that the author doesn't stick to ObjC naming
conventions.

Take for example the capitalize methods. In ruby, you have "capitalize" and
"capitalize!" to distinguish the immutable and mutable versions. To make this
distinction in ObjC, you generally use nouns vs. verbs. So for the equivalent
of ruby's "capitalize", you'd use "capitalizedString" (which is in fact
provided by NSString). But the mutable version, the equivalent of ruby's
"capitalize" should simply be "capitalize", not "capitalizedStringInPlace".

~~~
thingsdoer
-(NSString*)capitalizeInPlace; is the actual signature.

The reasoning for this is for consistency, while still maintaining
autocomplete proximity.

~~~
jakobe
I'm not really sure I understand; why would calling the method "capitalize"
instead of "capitalizeInPlace" be inconsistent?

(Also, the comments in the header file and the README file contain the name
"capitalizedStringInPlace" instead of "capitalizeInPlace")

Another inconsistency is that most mutating methods in ObjectiveC don't return
self, but either void or a boolean or an integer that reports if the method
succeeded. But I assume that this inconsistency is on purpose because you want
to make the methods chainable.

~~~
thingsdoer
The issue with the default syntax in NSString is that the mutating methods are
the more concise, but are also the ones you use the least. It makes far more
sense for the more used methods to be more concise than their mutating
siblings.

I don't disagree with you though. I'd prefer if the interface for this was
more idiomatic.

Returning void is sort of pointless. A boolean, maybe. I feel like returning
self is just making better use of things, really, and probably doesn't really
cause any confusion.

~~~
jakobe
Okay, now I get it, the naming makes autocomplete more convenient.

Returning void makes it easier to spot errors. If you accidentally use
"capitalizeInPlace" instead of "capitalizedString" your code will compile
without issues. If the mutating method returned void, it would result in a
compile error.

~~~
thingsdoer
That's an extreme edge case though, since if you're using a mutating method,
you're using a mutating string, and you're probably aware of that.

------
chrisdevereux
They look like convenient additions... but I'd be reluctant to add so many
category methods onto a Foundation class. Especially for un-prefixed methods.

If a future version of iOS adds an -sum method, for example, you'd better hope
it has the exact same semantics as yours, otherwise if the system calls -sum
expecting its implementation to be used, bad things (or worse, bad things with
no apparent cause) will happen when your implementation is used instead.

~~~
thingsdoer
I'd correct the category. Also, NSString is not going to change. If it does,
it will be rewritten extensively, most probably obsoleting this category.

~~~
chrisdevereux
Methods are often added to core classes like NSString. For example, in iOS 6:
[https://developer.apple.com/library/ios/releasenotes/General...](https://developer.apple.com/library/ios/releasenotes/General/iOS60APIDiffs/index.html)

And you changing the category won't help the versions already out in the wild.
Hopefully, automatic updates will mitigate this to some degree but not
everyone will turn them on.

There are workarounds (like prefixing methods with a pseudo-namespace), but
they're all a bit ugly. Might be worth considering though.

------
jph
Super! Are you motivated to do more like this?

I'll donate $100 to you if you want to continue with NS+Ruby classes.

~~~
thingsdoer
There are already a lot of Ruby categories out there. ObjectiveSugar covers a
lot of bases. I personally wouldn't import more Ruby categories. The NSString
API is a weak point of Cocoa, IMO, but in general I wouldn't like to see a
large amount of unique, dependent, astonishing code.

~~~
sjm
ObjectiveSugar:
[https://github.com/mneorr/ObjectiveSugar](https://github.com/mneorr/ObjectiveSugar)

~~~
danenania
Awesome! I hadn't seen this.

------
w0rdson
I have to add the obligatory pitch for just using RubyMotion. I use it/love
it, and def recommend it for those that have become a bit annoyed with the
verbose-ness of obj-c.

~~~
danenania
I love the idea of RM and would like to give it a try, but I keep hearing
murmurs about memory management issues and other little glitches that crop up
from time to time. I also hear that these kinds of problems get fixed very
quickly, but the idea of being stuck even for a short time while waiting for a
proprietary abstraction to be patched up makes me a bit hesitant to reach for
it for a serious app. Are these concerns overblown?

~~~
joshdotsmith
I'm writing a RM app right now and believe these concerns to be overblown.
They're overblown in the same way "Rails doesn't scale" is nonsense. The
addition of WeakRef to RM helps significantly. And you just have to look out
for gotchas.

If you want to be really convinced, check out RMQ:
[https://github.com/infinitered/rmq](https://github.com/infinitered/rmq). Has
made my life so easy.

------
andrewgross
A friend of mine made NSArray extensions with a Ruby syntax a while back.
Certainly useful if you find these helpful.

[https://github.com/nsantorello/nsarray-
extensions](https://github.com/nsantorello/nsarray-extensions)

------
sarreph
This is awesome and, as an Obj-C dev, is yet another thing that makes me want
to learn Ruby.

------
masklinn
Good, I was worried people could actually be able to correctly manipulate text
through NSString, that fixes it as it's impossible to not break text when
using Ruby strings.

~~~
thingsdoer
>> hn.txt

------
pdenya
Very impressive. I didn't know about objectAtIndexedSubscript and
objectForKeyedSubscript so I wouldn't have thought this was possible as a
category.

~~~
fleitz
Almost everything is possible via a category though a lot of it involves
hackery with objc/runtime.h

------
hamxiaoz
Is 'category' like a extension method in c#?

~~~
fleitz
Yeah, except you can add properties, though you have to do it with
objc_(s|g)etAssociatedObject

[https://developer.apple.com/library/ios/documentation/Cocoa/...](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html)

------
YoyosForUs
Wow, this looks really useful. Thanks for building this!

------
mamcx
Add a String format one, then is set!

~~~
thingsdoer
Still don't have a clever implementation.

~~~
mikeash
Unfortunately, although there's no particular reason for it, you're not
allowed to write a method that takes only variadic arguments. This doesn't
work:

    
    
        - (NSString *)format: ...;
    

It would be oh-so convenient, meaning you could write formatting operations
like this:

    
    
        newstr = [@"%d %@ %s" format: 42, @"blah", "yep"];
    

Given the constraints we have to work with, I'd say your best bet would be to
simply write a function:

    
    
        newstr = fmt(@"%d %@ %s", 42, @"blah", "yep");

~~~
koenigdavidmj
Why not just have it be a static method like stringWithFormat?

    
    
      + (id)stringWithFormat:(NSString *)format, ...;
    

This of course already exists, but if you wanted to do a Rubyfied version of
it, then just follow the same general pattern.

~~~
thingsdoer
The problem people have with the format implementation is that no matter what
you do, it's either obtuse shorthand, or incredibly verbose.

The reality is, that NSString needs native formatting sugar. Anything else
would really just be a hack. I'm not particularly even happy with the [@"Hello
":@"World] syntax, either.

~~~
mikeash
Here's a crazy idea:

    
    
        newstr = [@"%d %@" format 42, @"blah"];
    

Implement it as a method that takes a dummy parameter, plus a macro:

    
    
        - (NSString *)format:(int)dummy, ...
        #define format format:0,
    

Awful way to do it, but the resulting syntax is not entirely terrible.

~~~
thingsdoer
I'm not super comfortable with breaking message syntax like that. Also, very
wary of using a #define with a short oft used keyword in a library that will
be imported in majority of headers.

------
misiti3780
hell yes - im a python guy but this still looks great!

