rb_str_modify() equivalent in the Ruby language - ruby

I was trying to add a method to the String class. This method should mutate the current string (of course it would be possible to write a not mutating version but I'd prefer the mutating one). I had no idea how to do this and after some googling I found the method rb_str_modify which makes a given string mutable. That's exactly what I need but I couldn't find an equivalent in the Ruby language. Did I miss something or is there really no possibility in the language itself?

Reopening Classes
All classes in Ruby are open for extension so you can simply do this ...
Class String
def my_new_method(args)
# Some sort of modification to self
self.replace "SOME CALCULATED VALUE"
end
end
... somewhere in your code. I've modified string a few times in different applications - usually I just put the modifications into one particular module, making it easy to reuse them or remove them as required.
Modifying individual objects
Modifying a class in its entirety is dangerous as it's very difficult to identify all of the consequences - I once broke Merb by modifying a method in the String class. It's much safer to modify particular objects. This is easy in Ruby - you use the extend keyword. You define a module, add your function and then modify the target object. This example ...
module Humor
def tickle
"hee, hee!"
end
end
a = "Grouchy"
a.extend Humor
a.tickle » "hee, hee!"
is taken from the Pickaxe book
Chris

Related

Convert Strings to Class Names in ruby

I am trying to write a script in ruby which involves converting a string to Class Names. Since I am using pure ruby I cannot use .constantize.
I have tried using Object.const_get('String') but not sure why it is throwing a uninitialized constant String (NameError)
I have require 'active_support' on the top of the file
The conventional way of assigning a name to an anonymous class is as follows.
bub = Class.new do
def b
'hi'
end
end
str = 'Bubba'
Object.const_set(str, bub)
Bubba.is_a?(Class)
#=> true
Bubba.new.b
#=> "hi"
Is that what you want to do? If so, as you see, you need to use Module#const_set.
Do you try to use const_get only for a class or it is under a namespace like ModuleA::ModuleB::ClassName?
Also converting a string to a class name makes a new class or assigns the value to it?
I am asking these questions because the answer will affect the method you have to use. Maybe const_set instead of const_get is the correct approach, I don't know.
From the comments you gave it looks like 'String' is just an example and not the value that you literally pass to const_get. The actual value apparently is 'Assignment', is this correct?
When you execute Object.const_get('Assignment') and you receive the uninitialized constant error it indicates that at this point the class Assignment has not been loaded yet.
When you are using Rails then a lot of autoloading takes place if the files are in the right folder and the classes follow the naming conventions. Since you are running a "standalone" ruby script, autoloading does not take place and you will need to load the file yourself.
Adding a line like
require_relative "somepath/assignment"
should work. somepath needs to be adapted to the directory/file layout you have. It will load the file and execute the ruby code in that file.
If assignment.rb defines something like
class Assignment
end
Then the const_get will work.
That being said: what is your exact use case for this? Why do you need to dynamically find classes? Also Note that this opens up your app to (an unlikely) potential security issues if you let user input define what classes are loaded.

what is a variable/object/thing starting with a # in ruby

I am new to Ruby, so go easy :).
Anyway, I am trying to work out some stuff in the chef-provisioning-aws gem. One thing in particular is that there is an object called:
new_resource.driver.ec2_client
When I do an inspect on that object it returns exactly this:
#<Aws::EC2::Client>
So, my question is: what is this? What sort of "thing" in Ruby starts with a pound sign (hash) and has <...> in it?
Much appreciated.
The output of Ruby's inspect method is roughly like this unless you override it:
"#<#{self.class}:0x#{self.object_id.to_s(16)}"
So in other words: "#<ClassName:0xobject_id in hex>".
class Foo ; end
Foo.new.inspect
#=> "#<Foo:0x007ffe0eeea520>"
It seems that for Aws::EC2::Client it was overriden and does not include the object id.
It's the default implementation of the inspect method (although then the object ID should be included). It may be useful in some situations to implement your own method, so you can get an instant overview of what you want to know about this object. The # is just a random character and has no further meaning here.

Why is there no `.split!` in Ruby?

It just seems pretty logical to have it when there's even a downcase!. Has anyone else run into this use case in Ruby?
For the curious, I'm trying to do this:
def some_method(foo)
foo.downcase!.split!(" ")
## do some stuff with foo later. ##
end
some_method("A String like any other")
Instead of this:
def some_method(foo)
foo = foo.downcase.split(" ")
## do some stuff with foo later. ##
end
some_method("A String like any other")
Which isn't a really big deal...but ! just seems cooler.
Why is there no .split! in Ruby?
It just seems pretty logical to have it when there's even a downcase!.
It may be logical, but it is impossible: objects cannot change their class or their identity in Ruby. You may be thinking of Smalltalk's become: which doesn't and cannot exist in Ruby. become: changes the identity of an object and thus can also change its class.
I don't see this "use case" as very important.
The only thing a "bang method" is doing is saving you the trouble of assigning a variable.
The reason "bang methods" are the exception instead of the rule is they can produce confusing results if you don't understand them.
i.e. if you write
a = "string"
def my_upcase(string)
string.upcase!
end
b = my_upcase(a)
then both a and b will have transformed value even if you didn't intend to change a. Removing the exclamation point fixes this example, but if you're using mutable objects such as hashes and arrays you'll have to look out for this in other situations as well.
a = [1,2,3]
def get_last_element(array)
array.pop
end
b = get_last_element(a)
Since Array#pop has side effects, a is now 1,2. It has the last element removed, which might not have been what you intended. You could replace .pop here with [-1] or .last to get rid of the side effect
The exclamation point in a method name is essentially warning you that there are side effects. This is important in the concept of functional programming, which prescribes side effect free code. Ruby is very much a functional programming language by design (although it's very object oriented as well).
If your "use case" boils down to avoiding assigning a variable, that seems like a really minor discomfort.
For a more technical reason, though, see Jorg Mittag's answer. It's impossible to write a method which changes the class of self
this
def some_method(foo)
foo = foo.downcase.split(" ")
end
some_method("A String like any other")
is the same as this
def some_method(foo)
foo.downcase.split
end
some_method("A String like any other")
Actually, both of your methods return the same result. We can look at a few examples of methods that modify the caller.
array.map! return a modified original array
string.upcase! return a modified original string
However,
split modifies the class of the caller, changing a string to an array.
Notice how the above examples only modify the content of the object, instead of changing its class.
This is most likely why there isn't a split! method, although it's pretty easy to define one yourself.
#split creates an array out of a string, you can't permanently mutate(!) the string into being an array. Because the method is creating a new form from the source information(string), the only thing you need to do to make it permanent, is to bind it to a variable.

Built-in way to determine whether a string is a Ruby reserved word?

Is there something built-in with Ruby to determine if a string is a reserved word? Something like "next".is_keyword??
The only way I can think of is loading an array with all the keywords you know about.
class String
def is_keyword?
%w{__FILE__ __LINE__ alias and begin BEGIN break case class def defined? do else elsif end END ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield}.include? self
end
end
"foobar".is_keyword? # => false
"for".is_keyword? # => true
For reference:
I know this isn't a built-in way, it's just the only way I could think of. Don't downvote me for it.
The list I included is that of true keywords. public, protected and friends aren't really keywords, just the names of important methods which are called during the creation of modules or classes. You can think of it as elements of the Ruby DSL.
As far as I know, protected isn't really a reserved word. It's just the name of an important method.
http://wiki.rubyonrails.org/rails/pages/reservedwords lists reserved words you can't use (some of them only apply if you're using Rails or its dependencies), and method names that can cause problems.
If this doesn't fully answer your question, can you define more fully whether you're interested in method names or variable names, and whether you're worried about words that can't be used at all, or words that may cause other things to go wrong?
Use Ruby gem rubykeyword. It does more than identifying the keyword. string.keyword? tells you if its keyword or not. string.define gives a definition of the keyword. There is string.example too.
If you have a class where you want to implement a method called "protected", then before you define that method make an instance of that class and call
instance.methods
This will show you all the methods inherited for the class, and if "protected" is there then it is reserved by ruby.

Reclassing an instance in Python

I have a class that is provided to me by an external library. I have created a subclass of this class. I also have an instance of the original class.
I now want to turn this instance into an instance of my subclass without changing any properties that the instance already has (except for those that my subclass overrides anyway).
The following solution seems to work.
# This class comes from an external library. I don't (want) to control
# it, and I want to be open to changes that get made to the class
# by the library provider.
class Programmer(object):
def __init__(self,name):
self._name = name
def greet(self):
print "Hi, my name is %s." % self._name
def hard_work(self):
print "The garbage collector will take care of everything."
# This is my subclass.
class C_Programmer(Programmer):
def __init__(self, *args, **kwargs):
super(C_Programmer,self).__init__(*args, **kwargs)
self.learn_C()
def learn_C(self):
self._knowledge = ["malloc","free","pointer arithmetic","curly braces"]
def hard_work(self):
print "I'll have to remember " + " and ".join(self._knowledge) + "."
# The questionable thing: Reclassing a programmer.
#classmethod
def teach_C(cls, programmer):
programmer.__class__ = cls # <-- do I really want to do this?
programmer.learn_C()
joel = C_Programmer("Joel")
joel.greet()
joel.hard_work()
#>Hi, my name is Joel.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.
jeff = Programmer("Jeff")
# We (or someone else) makes changes to the instance. The reclassing shouldn't
# overwrite these.
jeff._name = "Jeff A"
jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>The garbage collector will take care of everything.
# Let magic happen.
C_Programmer.teach_C(jeff)
jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.
However, I'm not convinced that this solution doesn't contain any caveats I haven't thought of (sorry for the triple negation), especially because reassigning the magical __class__ just doesn't feel right. Even if this works, I can't help the feeling there should be a more pythonic way of doing this.
Is there?
Edit: Thanks everyone for your answers. Here is what I get from them:
Although the idea of reclassing an instance by assigning to __class__ is not a widely used idiom, most answers (4 out of 6 at the time of writing) consider it a valid approach. One anwswer (by ojrac) says that it's "pretty weird at first glance," with which I agree (it was the reason for asking the question). Only one answer (by Jason Baker; with two positive comments & votes) actively discouraged me from doing this, however doing so based on the example use case moreso than on the technique in general.
None of the answers, whether positive or not, finds an actual technical problem in this method. A small exception is jls who mentions to beware of old-style classes, which is likely true, and C extensions. I suppose that new-style-class-aware C extensions should be as fine with this method as Python itself (presuming the latter is true), although if you disagree, keep the answers coming.
As to the question of how pythonic this is, there were a few positive answers, but no real reasons given. Looking at the Zen (import this), I guess the most important rule in this case is "Explicit is better than implicit." I'm not sure, though, whether that rule speaks for or against reclassing this way.
Using {has,get,set}attr seems more explicit, as we are explicitly making our changes to the object instead of using magic.
Using __class__ = newclass seems more explicit because we explicitly say "This is now an object of class 'newclass,' expect a different behaviour" instead of silently changing attributes but leaving users of the object believing they are dealing with a regular object of the old class.
Summing up: From a technical standpoint, the method seems okay; the pythonicity question remains unanswered with a bias towards "yes."
I have accepted Martin Geisler's answer, because the Mercurial plugin example is a quite strong one (and also because it answered a question I even hadn't asked myself yet). However, if there are any arguments on the pythonicity question, I'd still like to hear them. Thanks all so far.
P.S. The actual use case is a UI data control object that needs to grow additional functionality at runtime. However, the question is meant to be very general.
Reclassing instances like this is done in Mercurial (a distributed revision control system) when extensions (plugins) want to change the object that represent the local repository. The object is called repo and is initially a localrepo instance. It is passed to each extension in turn and, when needed, extensions will define a new class which is a subclass of repo.__class__ and change the class of repo to this new subclass!
It looks like this in code:
def reposetup(ui, repo):
# ...
class bookmark_repo(repo.__class__):
def rollback(self):
if os.path.exists(self.join('undo.bookmarks')):
util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
return super(bookmark_repo, self).rollback()
# ...
repo.__class__ = bookmark_repo
The extension (I took the code from the bookmarks extension) defines a module level function called reposetup. Mercurial will call this when initializing the extension and pass a ui (user interface) and repo (repository) argument.
The function then defines a subclass of whatever class repo happens to be. It would not suffice to simply subclass localrepo since extensions need to be able to extend each other. So if the first extension changes repo.__class__ to foo_repo, the next extension should change repo.__class__ to a subclass of foo_repo and not just a subclass of localrepo. Finally the function changes the instanceø's class, just like you did in your code.
I hope this code can show a legitimate use of this language feature. I think it's the only place where I've seen it used in the wild.
I'm not sure that the use of inheritance is best in this case (at least with regards to "reclassing"). It seems like you're on the right track, but it sounds like composition or aggregation would be best for this. Here's an example of what I'm thinking of (in untested, pseudo-esque code):
from copy import copy
# As long as none of these attributes are defined in the base class,
# this should be safe
class SkilledProgrammer(Programmer):
def __init__(self, *skillsets):
super(SkilledProgrammer, self).__init__()
self.skillsets = set(skillsets)
def teach(programmer, other_programmer):
"""If other_programmer has skillsets, append this programmer's
skillsets. Otherwise, create a new skillset that is a copy
of this programmer's"""
if hasattr(other_programmer, skillsets) and other_programmer.skillsets:
other_programmer.skillsets.union(programmer.skillsets)
else:
other_programmer.skillsets = copy(programmer.skillsets)
def has_skill(programmer, skill):
for skillset in programmer.skillsets:
if skill in skillset.skills
return True
return False
def has_skillset(programmer, skillset):
return skillset in programmer.skillsets
class SkillSet(object):
def __init__(self, *skills):
self.skills = set(skills)
C = SkillSet("malloc","free","pointer arithmetic","curly braces")
SQL = SkillSet("SELECT", "INSERT", "DELETE", "UPDATE")
Bob = SkilledProgrammer(C)
Jill = Programmer()
teach(Bob, Jill) #teaches Jill C
has_skill(Jill, "malloc") #should return True
has_skillset(Jill, SQL) #should return False
You may have to read more about sets and arbitrary argument lists if you aren't familiar with them to get this example.
This is fine. I've used this idiom plenty of times. One thing to keep in mind though is that this idea doesn't play well with old-style classes and various C extensions. Normally this wouldn't be an issue, but since you are using an external library you'll just have to make sure you're not dealing with any old-style classes or C extensions.
"The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change it's class." - Head First Design Pattern. Something very similar write Gamma et.al. in their Design Patterns book. (I have it at my other place, so no quote). I think that's the whole point of this design pattern. But if I can change the class of an object at runtime, most of the time i don't need the pattern (there are cases when State Pattern does more than simulate a class change).
Also, changing class at runtime doesn't always work:
class A(object):
def __init__(self, val):
self.val = val
def get_val(self):
return self.val
class B(A):
def __init__(self, val1, val2):
A.__init__(self, val1)
self.val2 = val2
def get_val(self):
return self.val + self.val2
a = A(3)
b = B(4, 6)
print a.get_val()
print b.get_val()
a.__class__ = B
print a.get_val() # oops!
Apart from that, I consider changing class at runtime Pythonic and use it from time to time.
Heheh, fun example.
"Reclassing" is pretty weird, at first glance. What about the 'copy constructor' approach? You can do this with the Reflection-like hasattr, getattr and setattr. This code will copy everything from one object to another, unless it already exists. If you don't want to copy methods, you can exclude them; see the commented if.
class Foo(object):
def __init__(self):
self.cow = 2
self.moose = 6
class Bar(object):
def __init__(self):
self.cat = 2
self.cow = 11
def from_foo(foo):
bar = Bar()
attributes = dir(foo)
for attr in attributes:
if (hasattr(bar, attr)):
break
value = getattr(foo, attr)
# if hasattr(value, '__call__'):
# break # skip callables (i.e. functions)
setattr(bar, attr, value)
return bar
All this reflection isn't pretty, but sometimes you need an ugly reflection machine to make cool stuff happen. ;)
This technique seems reasonably Pythonic to me. Composition would also be a good choice, but assigning to __class__ is perfectly valid (see here for a recipe that uses it in a slightly different way).
In ojrac's answer, the break breaks out of the for-loop and doesn't test any more attributes. I think it makes more sense to just use the if-statement to decide what to do with each attribute one at a time, and continue through the for-loop over all attributes. Otherwise, I like ojrac's answer, as I too see assigning to __class__ as weird. (I'm a beginner with Python and as far as I remember this is my first post to StackOverFlow. Thanks for all the great information!!)
So I tried to implement that. I noticed that dir() doesn't list all the attributes. http://jedidjah.ch/code/2013/9/8/wrong_dir_function/ So I added 'class', 'doc', 'module' and 'init' to the list of things to add if they're not there already, (although they're probably all already there), and wondered whether there were more things dir misses. I also noticed that I was (potentially) assigning to 'class' after having said that was weird.
I will say this is perfectly fine, if it works for you.

Resources