Continuing going through the array methods, using Ruby 1.9.3
Element Reference
ary[index] → obj or nil
ary[start, length] → new_ary or nil
ary[range] → new_ary or nil
slice(index) → obj or nil
slice(start, length) → new_ary or nil
slice(range) → new_ary or nil
Ok, so we’ve got the “normal” way to access an array element, simply using the name of the array, [ index ]. If item is not found at index it returns nil.
Then we have passing a start index and a length. A friend was working on rubykoans.com had question I couldn’t answer - Why is ary[4,0] an empty array and not nil?
12345678910
>>ary=%w(one two three four)=>["one","two","three","four"]>>ary[0,0]#expected=>[]>>ary.index(ary.last)# index of last item is 3=>3>>ary[4,0]# not expected, no index of 4 exists ?? why return empty array =>[]>>ary[5,0]# expected, no index of 5=>nil
So yes, thats very confusing… why is it returning an empty array for last_index+1 of the array??
Moving on .. Passing a range is another way to access elements
I tried accessing an index greater than the end and it works as expected
123456
>>ary[0..3]# all the elements=>["one","two","three","four"]>>ary[1..2]# just index 1 and 2=>["two","three"]>>ary[1..5]# accessing off the end of array=>["two","three","four"]
It looks as though slice is alias for [ ] … so everything should work the same.
Element Assignment
ary[index] = obj → obj
ary[start, length] = obj or other_ary or nil → obj or other_ary or nil
ary[range] = obj or other_ary or nil → obj or other_ary or nil
This works on an array which is a collection of arrays, and this method will find the first array where the first key matches obj. Odd, not sure when I would use this.
at(index) → obj or nil
Same thing as ary[index] .. maybe it would read better, but I’m so used the [ ] syntax, I will probably use that syntax
clear → ary
Clear, removes all elements in the array. Didn’t know this was there.
collect/map
collect {|item| block } → new_ary
map {|item| block } → new_ary
collect → an_enumerator
map → an_enumerator
Not the same collect that is in enumerable, it runs the block for each item in the array and returns an array of results.
12345678910
>>%w(red blue green yellow orange).collect{|w|w.upcase}=>["RED","BLUE","GREEN","YELLOW","ORANGE"]>>%w(red blue green yellow orange).map(&:upcase)=>["RED","BLUE","GREEN","YELLOW","ORANGE"]>>%w(red blue green yellow orange).map(&:upcase).object_id=>70349437828620>>%w(red blue green yellow orange).object_id=>70349434016460
You can give it a block or a “symbol to proc”, that is the funny &: followed by a method name. When I first saw that I said what the heck is that? and what is it doing? I mean, how do you google for something like that? I finally found out what it was called…”symbol to proc” and now I use it everywhere it makes sense. So Map and Collect appear to be synonyms here. Did not know that… Usually, I use collect over map since that makes more sense to me, you are collecting results.
That is all for this post, I can replace arrays in to arrays, now I know that collect and map are the same on arrays. Still there is the nagging problem of why on a 4 element array ary[4,0] returns an empty array instead of nil. Anyone know?
My second blog post on the topic. Between the writings of this post and part 1 Ruby 2.0 was released on its 20th birthday! But I am going to stick with Ruby 1.9.3 for this series, maybe after I am done I’ll see what changed for 2.0
BTW, to make an array you can use the %w and space separated list of values, I will use that here to save on typing.
ary & other_ary → new_ary
Set Intersection—Returns a new array containing elements common to the two arrays, with no duplicates.
Oooh this sounds like math, specifically Set Theory. I did this in college but didn’t remember the ‘no duplicates’ part so I looked it up. The definition for Intersection from wikipedia is “the intersection of two sets A and B is the set that contains all elements of A that also belong to B (or equivalently, all elements of B that also belong to A), but no other elements.” So no room for duplicates there either.
If I wanted to know what ingredients I need to be sure to get enough of for baking I could make some arrays like that and get the intersection of them. Whoa I thought & for bitwise operation? Well Yes it is!! But that is for Fixnum objects. With arrays the & is an intersection! Cool .. polymorphism for the win!
Next is the * operator with two usages:
ary * int → new_ary
ary * str → new_string
Repetition—With a String argument, equivalent to self.join(str). Otherwise, returns a new array built by concatenating the int copies of self.
I made an array for days of the week, then used * 4 to make a 4 week month. Seems pretty awesome to something like this without having to loop to build arrays.. if I didn’t use that I would have to write code like this:
That all being said, if you want to combine an array 4 times, use * and it is easy :)
There’s other ways that might be better, but you get the idea. Much shorter to use the * int :) lets try the other version.
1234
>>title=%w(Samuel E. Jones)=>["Samuel","E.","Jones"]>>title*" "=>"Samuel E. Jones"
The parameter after the * is the character to join with, basically it is calling join.
12
>>title.join(" ")=>"Samuel E. Jones"
I probably would use join since that makes it more clear to the reader what you are doing and it is more common. But if you are going for ruby golf, then use the * ” ”
Array Difference---Returns a new array that is a copy of the original array, removing any items that also appear in other_ary. (If you need set-like behavior, see the library class Set.)
123456
>>colors=%w(red purple blue green yellow orange)=>["red","purple","blue","green","yellow","orange"]>>primary_colors=%w(red blue yellow)=>["red","blue","yellow"]>>secondary_colors=colors-primary_colors=>["purple","green","orange"]
Also pretty straight forward.
ary << obj → ary
Append—Pushes the given object on to the end of this array. This expression returns the array itself, so several appends may be chained together.
Commonly called the shovel operator you can add something to the end of the array, and since it returns an array you can do it multiple times
without the extra parenthesis. Cool, I hadn’t realized you could chain << before now!
Next, a method with a funny name. <=>
ary <=> other_ary → -1, 0, +1 or nil
Comparison—Returns an integer (-1, 0, or +1) if this array is less than, equal to, or greater than other_ary. Each object in each array is compared (using <=>). If any value isn’t equal, then that inequality is the return value. If all the values found are equal, then the return is based on a comparison of the array lengths. Thus, two arrays are “equal” according to Array#<=> if and only if they have the same length and the value of each element is equal to the value of the corresponding element in the other array.
I’ve only seen this used when writing custom methods to determine equality, but it seems pretty straight forward. I will play with it when I play around with enumerable.
ary == other_ary → bool
Equality—Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object.==) the corresponding element in the other array.
Everytime that I have to lookup something with hashes or arrays, I find lots of methods that I didn’t know about, so I thought I’d do an experiment where I will learn about each one and write some examples and try to understand how to use it. I kind of picture someone sitting next to me as I do this, reading the docs and trying them out with me.
Class methods always start with the name of the class, dot, followed by method name. For example, we can
call Time.now as a class method on the Time class, which returns a new Time object initialized with the current time.
Docs say:
[](*args)
[](*args)
Returns a new array populated with the given objects.
There are three usage examples in the docs, lets try them out and see what they do, first:
1234
>>Array.[](1)=>[1]>>Array.[](1,2,3)=>[1,2,3]
The method name is [] and the params is *args which is the splat operator which takes any number of objects. Interesting I’ve never seen this used in the real world. I am sure its used cleverly, I just don’t see it! I showed this to a friend Danielle Sucher and she said:
I actually always think it’s nifty that something like
a[0] can be called with a.send(:[], 0) instead. Makes it possible to
do stuff like a.try(:[], 0) or a.tap{}.send(:[], 0).
Thanks!! Moving on..
12
>>Array['a','b','c']=>["a","b","c"]
Returns array with the contents of *args just as it says. This is one way you can be “confident” of your code as Avdi talked about in Confident Coding . If you want an array, make sure its an array! if its not an array it will put it inside an array like this:
1234
>>Array(1)=>[1]>>Array([1])=>[1]
Parentheses is optional in ruby so these are the same:
Looks funny without the () doesn’t? I almost always use () for methods. Helps later on if you decided to add more things on that line you don’t have to go back and add them. See Avdi’s RubyTapas Episode 024 Incidental Change $9 a month screencasts that come out 3x week, so good!! Sign up now! :)
And lastly, the way you might normally create arrays, with [ *args ]. I tried to dig through Kernel to see if [] was a method on kernel that would call Array.new but I couldn’t find anything. So I am still puzzled about how this actually works. Maybe a reader has an insight?
12
>>[1,2,3]=>[1,2,3]
Array.new
new(size=0, obj=nil)
new(array)
new(size) {|index| block }
Returns a new array.
So if no params, default is size 0 and value of index 0 is nil
1234
>>a=Array.new=>[]>>a[0]=>nil
Creates an empty array. Default value is nil.
If you pass a single param, it makes an array of that size.
So the default value of each element is the string “-empty-” and they are in fact the same object.
Lets create an array of basic family members, adding it to her_side and his_side. Then I added another family member to his_side and prove they are copies of the parents and not the same object.
Interesting, maybe if you wanted an array like this
12
>>b=Array.new(5){|index|index*5}=>[0,5,10,15,20]
Cool!
try_convert(obj) -> array or nil
Tries to convert obj into an array, using to_ary method. Returns the converted array or nil if obj cannot be converted for any reason. This method can be used to check if an argument is an array.
Hmm, so I guess this would be good if you only want to return array if its an array and nil otherwise. Never seen it used myself but it be a way to write confident code if you only want to respond to nil or array and use a bunch of if statements.
Cool, I had fun poking at ruby array class methods and trying things out. Be sure and checkout the gotchas in the docs. I hope I was able to shed some light or at least make you think about some of the public methods of arrays. If you have some insight on how some of these work, please leave a note in the comments.
Thank you to Danielle Sucher@DanielleSucher for helping by proof-reading this post as I am working on improving my writing.
Next post in this series will be on instance methods!
I wanted to buy “Practical Object-Orientated Design in Ruby” by Sandi Metz when it first came out, and I had a hard time justifying it because there are many books I have bought and have not read all the way through. So I thought I’d do an experiment in reading a tech book cover-to-cover and then I’ll buy “poodr”. So my first cover-to-cover read was Eloquent Ruby by Russ Olsen. Not all books should be read cover-to-cover but when you read a book cover-to-cover you’ll discover a few things:
what topics are there and how deep they are
what topics are not
the sequence and structure of the book, about where things are so its easier to flip back to review
And lastly, you’ll be able to speak authoritatively to someone when you say “Read this book!”
I bought Eloquent Ruby perhaps 1.5 years ago, and after the first couple chapters decided it was the most awesome book ever and how much smarter I would have been had I gotten it sooner. I read maybe 1/3 of the way through, I skipped around some, the testing chapters and the metaprogramming. Even with skipping around in the book, I quickly became an evangelist for this book. I told every ruby developer I encountered to buy it, I even got a copy for my last company. It’s just plain good, you’ll learn the ruby idioms and why. I’ve been programming since I was 13 and got pretty good at memorizing the syntax of things, not truly understanding why or how, but “type this thing to do that thing”. But Eloquent Ruby helped me understand why behind the syntax. Now that I understand “why”, it is so much easier to remember without relying on memorization.
That is why I chose this book to read as my first cover-to-cover read.
I needed a way to keep track of my progress since I use different devices and software (mac, iphone, ipad, android nexus) I can’t rely on a cloud service to “sync my place” across all of them. I use an Evernote note with all the chapters as a checkbox list. Plus, I love checking things off a list. I would see my progress and be able to pick back up where I left off each reading session. The chapters in Eloquent Ruby are pretty short, so it was easy to read in small chunks of time. I read it at break at work, on the bike at the gym, riding in car, just about anywhere. It took a couple months to get through all the chapters this way.
It didn’t take long to realize one of the benefits of reading cover-to-cover. When I was almost done with the book, a friend was having problems with some concept in ruby and I remembered there was a chapter about it, near the beginning of the book. I flipped around a few minutes and found the prefect chapter for her to read. Had I not read it cover-to-cover I may not have known that content was there or wouldn’t have been as confident recommending it and my “find it in this chapter” instructions.
My “reward” for finishing Eloquent Ruby was to get Sandi Metz’s book “Practical Object-Orientated Programming in Ruby”.
I followed the same process and created a list of chapters in Evernote, planning to read them in bits at home, gym and work breaks. At only 247 pages, it is quite a bit shorter than Eloquent Ruby with 447 pages so I knew it would take alot less time.
Chapter 1 came easily enough and I checked it off. Then I was surprised to find out what followed was that I could not put the book down. Instead of my next reading time or gym appointment, I read till 2 in the morning, picked back up and finished it the next morning (it probably helped that I was home sick with the weekend to myself). I was so excited about what I was learning, I wanted to stop reading and refactor code I wrote a few days ago. I so wanted to skip ahead to Chapter 9 on tests. However, I stuck to original plan of cover-to-cover and read all the way through. It is an incredible book.
I say incredible not just because “I learned the right way” but because it validated so many instincts and gut feelings I have about class design. Having those things in writing gives a source to “cite” in discussions and confidence to say “Yes, this is how we will do this thing”.
So as a result of my experiment I would recommend these two things to anyone wanting to improve their knowledge of ruby:
Get these two books.
Read them cover-to-cover.
I’m confident that you will enjoy both the information and the reading experience.
BTW these are affiliate links, maybe I’ll earn enough to get a cup of coffee eventually.
I needed a simple breadcrumb module/class that would let me set the first crumb and add to it later. I looked at www.ruby-toolbox.com and saw a bunch, none of them looked simple enough for me. I already had a template so I dont care about changing that…so I whipped up my own breadcrumbs:
After watching www.rubytapas.com talk about using Struct (I had never really used it before or understood why not just make a class). At first I defined crumb outside of Breadcrumb, then after I had tests, moved inside and it still worked. It seems a bit odd, to have that inside Breadcrumb, but its only accessible inside Breadcrumb so I guess that is good.
1234567891011121314151617181920212223242526272829
describeBreadcrumbdodescribe'#new'doit'sets default crumb of Home /'do@breadcrumb=Breadcrumb.new@breadcrumb.shouldhave(1).crumb@breadcrumb.crumbs.first.name.should=='Home'@breadcrumb.crumbs.first.link.should=='/'endit'sets initial crumb of Main /main'do@breadcrumb=Breadcrumb.new('Main','/main')@breadcrumb.shouldhave(1).crumb@breadcrumb.crumbs.first.name.should=='Main'@breadcrumb.crumbs.first.link.should=='/main'endenddescribe'#add'doit'a second crumb'do@breadcrumb=Breadcrumb.new@breadcrumb.add('Products','/products')@breadcrumb.shouldhave(2).crumbsendend
output of spec doc
123456
Breadcrumb#newsetsdefaultcrumbofHome/setsinitialcrumbofMain/main #add a second crumb
The other day I was working a project where I had to validate some input before running a query:
Say I have a database of friends and their address, and I want to find all friends with at least 3 letters of the name and an optional zipcode. The controller looks like this:
12345678910111213141516171819
defindex@name=clean_name(params[:name])@zip=params[:zip]if@name.present?&&@name.size>2if@zip.present?&&@zip.match(/^\d{5}$/)@friends=Property.where("name like ?","%#{@name}%").where("zip_code = ?",@zip)else@friends=Property.where("name like ? ","%#{@name}%")endelse@friends=[]endendprivatedefclean_name(str="")str.gsub(/mrs?|miss|ms|jr|sr/i,"").stripifstr.present?end
Ugly huh? Too many if statement and validation and checking for blanks. I was in a rush, so I was trying to get it out there and move on with life, but when I needed the same validation in another action, I figured it was time to bite the bullet and Do It The Right Way.
I started off with a plain old ruby object (PORO) in lib directory so I can validate the params for a search query there (in past, I’ve put objects like this in models since its sort of a model, just not a database model, so .. I am 50/50 on the issue. Meh. I’ll figure out the best location later if need be).
defindex@search_params=SearchParams.new(params)if@name.present?&&@name.size>2if@zip.present?&&@zip.match(/^\d{5}$/)@friends=Property.where("name like ?","%#{@search_params.name}%").where("zip_code = ?",@search_params.zip)else@friends=Property.where("name like ? ","%#{@search_params.name}%")endelse@friends=[]endend
And now that it param in its own class, its much easier to test (I personally despise testing controllers)..and that private method is out of the controller, yay!
123456789101112131415161718192021222324
describeSearchParamsdoit"should initialize the Search object"do@search=SearchParams.new(name:"blah",zip_code:"12345")@search.name.should=="blah"@search.zip_code.should=="12345"endcontext"clean name"doit"should clean name modifiers from search query"dokeywords=%w(mr mrs miss jr sr)keywords.eachdo|keyword|@search=SearchParams.new(name:"#{keyword} Bob",zip_code:"12345")@search.name.should=="Bob"endkeywords.eachdo|keyword|@search=SearchParams.new(name:"blah #{keyword.upcase!}",zip_code:"12345")@search.name.should=="Bob"endendendend
That first test is just sort of a sanity test, to make sure everything is working. I may delete it later. Then I test cleaning the modifiers both lowercase and uppercase to confirm the case insensitivity of the regex (maybe not necessary). The each loop there actually makes several tests in loop.
defindex@search_params=SearchParams.new(params)if@search_params.valid?if@search_params.zip_code.present?@friends=Friend.where("name like ?","%#{@search_params.name}%").where("zip_code = ?",@search_params.zip_code)else@friends=Friend.where("name like ? ","%#{@search_params.name}%")endelse@friends=[]endend
Looks better, we can just do a .valid? call to see if the name is of valid length and the zipcode (if its provided) meets the the requirements of 5 digits. Nicely refactored and now its easier to test. Now we can test the validations:
123456789101112131415161718192021
context"validations"doit"should not be valid for name length of 1"do@search=SearchParams.new(name:"b")@search.should_notbe_validendit"should be valid for name length of 3"do@search=SearchParams.new(name:"bla")@search.shouldbe_validendit"should allow blank for zip_code"do@search=SearchParams.new(name:"blah",zip_code:"")@search.shouldbe_validendit"should not allow 1 for zip_code"do@search=SearchParams.new(name:"blah",zip_code:"1")@search.should_notbe_validendend
BTW since there is a method called valid? and it returns a boolean (obviously with the ? at end) in rspec you can just do be_whatever to call that method in your tests.
Beautiful!! … I sleep better tonight knowing I’ve made beautiful code :) :) :) :)
For one of my projects we have started doing code reviews. We use github, work in a branch, then submit a pull request for review. Looking at github you can see a nice diff of the changes and you are able to add comments. So github is one way. You could also just use
1
git diff master..myawesomebranch
And get a decent diff.
I prefer to code review live if the other person is available in person (screensharing would work too). It makes it easy to ask why this, and did you consider this and then after discussion you can make a note of what to change.
Its super easy to nit pick at someones code, after all programming is alot of your personal style. But there are sometimes where you say “umm ok thats different, cool lets move on” and sometimes where you can say “hmm, what do you think of this instead” like for example
123
unless something == "something" && !this.method(that) do
// this awesome thing
end
yes it works (but I didn’t question if it works or not, I’m thinking of humans reading this code later!), but lets consider:
123
if something != "something" && this.method(that) do
// this awesome thing
end
I think its a little more readable, but when I make suggestions I like to open the door for discussion, and perhaps I don’t understand all the code and it gives the other person to explain it. Sometimes they answer with “oh well i didn’t write that part” .. That is OK!! when I do a code review I am taking it as you saying “hey this code was my responsibility, I added some code, fixed some confusing parts and submit it you for review.”
I rarely do git blame to see who did something because it doesn’t matter most of the time who did that weird bit of code. Most likely it was a build up of code and the author didn’t stop to think about refactoring, or he/she was under time constraints. That’s the normal evolution of programming and we are trying to break that habit with reviews. But if I find a confusing bit of code that I can’t figure out, then maybe I’ll do git blame to see who last edited that so I can go to them and ask for some help in understanding it. Coding is never a perfect process. This is why code reviews are good.
I like code reviews alot and have done them at a few different companies and with people having the right attitudes it goes a long way to making better code.
I’ve seen people use const_get(“string”) to get the objectived (yes I make up my own words, I don’t know what you would call this? perhaps constantized? keep reading) of a string like:
123456
>>t=Object.const_get("Talk")=>Talk(id:integer,conference_id:integer,person_id:integer,title:string,description:text,slides_url:string,video_url:string,start_time:datetime,end_time:datetime,created_at:datetime,updated_at:datetime)>>intro_talk=t.new(title:"Intro to Rails")t.ancestors[0]=>Talk(id:integer,conference_id:integer,person_id:integer,title:string,description:text,slides_url:string,video_url:string,start_time:datetime,end_time:datetime,created_at:datetime,updated_at:datetime)
Crazy, huh? We look up the constant “Talk” (a subclass of ActiveRecord) and assign it to ‘t’ and use that to instantiate a new record. I don’t know why you’d do this, but this is what it’s doing and since today I learned that any uppercased ruby identifier is an constant that all makes perfect sense. We can look at the first ancestors and see its ancestor is Talk.
From time to time I run through the rubykoans…each time remembering or picking up something new. I’m such a dork, I keep a log of the dates in a spreadsheet. I first did these in Dec 2009, then again in July 2010, May 2011 and now I am going through them again. I remember the first time I did a few, I was amazed “how did they do that!?!?!” and dug through the source to see how it works. I immediately emailed Joe O’Brien and Jim Weirich at edgecase.com and thanked them! Joe thanked me for my kind words and Jim said they were inspired by the book Little Lisper.
When I first did these in 2009, it was a github repo that you cloned. Now you can go to www.rubykoans.com and download a zipfile or work on them through the browser! Few months ago I was bored with no real computer, so I attempted the browser based koans on my Samsung Tablet. It was kinda hard to do the special symbols so I don’t really recommend doing it on a tablet unless you merely wanted to kill time like I did. :)
I’ve read about emberjs and I’ve tried CodeSchool Backbone and the concepts are interesting, I like the concept of a model updating some text on the screen without having to write $(‘#myelement’).text(‘updated content’) and a friend was mentioning how much they like the emberjs models. So, I wanted to try and in a way I could only worry about a few pieces (that router and junk still kinda makes me crazy for frontend since I do that on the back end.. maybe I just need to do more). I was reading the Ember Documentation and they have some small examples that inspired me. So I set out to try somethings:
I downloaded the Starter Kit from emberjs.com and it had a skeleton index and app.js file ready to go. Nice. I first played around with making a model and calling a method on it.