-
25
SEP
2014Regex Code Equivalency
#!/usr/bin/env ruby -w Name = "Gray, James" !!(Name =~ /\AGray/) # => true Name.start_with?("Gray") # => true !!(Name =~ /James\z/) # => true Name.end_with?("James") # => true !!(Name =~ /Dana/) # => false Name.include?("Dana") # => false !!(Name =~ /\A\z/) # => false Name.empty? # => false !!(Name =~ /\AGray, James\z/) # => true Name == "Gray, James" # => true !!(Name =~ /\A(?:Gray, James|Gray, Dana)\z/) # => true ["Gray, James", "Gray, Dana"].include?(Name) # => true Name =~ /\A\w+/ && $& # => "Gray" Name[/\A\w+/] # => "Gray" Name =~ /\A(\w+),\s*(\w+)\z/ && $2 # => "James" Name[/\A(\w+),\s*(\w+)\z/, 2] # => "James" Name =~ /\A(?<last>\w+),\s*(?<first>\w+)\z/ && $~[:first] # => "James" Name[/\A(?<last>\w+),\s*(?<first>\w+)\z/, :first] # => "James" Name.scan(/^.*\n?/) # => ["Gray, James"] Name.lines # => ["Gray, James"] Name.scan(/./m) # => ["G", "r", "a", "y", ",", " ", "J", "a", "m", "e", "s"] Name.chars # => ["G", "r", "a", "y", ",", " ", "J", "a", "m", "e", "s"] Name.gsub(/[aeiou]/, "") # => "Gry, Jms" Name.delete("aeiou") # => "Gry, Jms" Name.gsub(/[aeiou]/, "X") # => "GrXy, JXmXs" Name.tr("aeiou", "X") # => "GrXy, JXmXs" # For the destructive operations that follow you can drop the `dup()` and # switch `sub()` to `sub!()`, as long as you don't care about the return value. Name.sub(/(?=,)/, " II") # => "Gray II, James" Name.dup.insert(Name.index(","), " II") # => "Gray II, James" Name.sub(/\A/, "Name: ") # => "Name: Gray, James" Name.dup.prepend("Name: ") # => "Name: Gray, James" Name.sub(/\A.*\z/m, "Gray, Dana") # => "Gray, Dana" Name.dup.replace("Gray, Dana") # => "Gray, Dana" Name.sub(/\A.*\z/m, "") # => "" Name.dup.clear # => "" Spacey = "\tsome space\r\n" Spacey.sub(/\A\s+/, "") # => "some space\r\n" Spacey.lstrip # => "some space\r\n" Spacey.sub(/\s+\z/, "") # => "\tsome space" Spacey.rstrip # => "\tsome space" Spacey.sub(/\A\s*(.+?)\s*\z/m, '\1') # => "some space" Spacey.strip # => "some space" Spacey.sub(/(?:\r?\n|\r)\z/m, "") # => "\tsome space" Spacey.chomp # => "\tsome space" Spacey.sub(/(?:\r\n|.)\z/m, "") # => "\tsome space" Spacey.chop # => "\tsome space" Spacey.gsub(/ +/, " ") # => "\tsome space\r\n" Spacey.squeeze(" ") # => "\tsome space\r\n"
-
27
AUG
2014Which Types to Type
I've mentioned before that I'm writing some Rust code, specifically an RPN calculator as a simple exercise. I'm going to dump the code here so we can discuss one aspect of it, but do remember that I'm very new to Rust and this code could surely be better:
use std::fmt; use std::os; struct Stack { numbers: Vec<f64> } impl Stack { fn new() -> Stack { Stack{numbers: vec![]} } fn is_empty(&self) -> bool { self.numbers.is_empty() } fn push(&mut self, number: f64) { self.numbers.push(number); } fn result(&self) -> f64 { *self.numbers.last().expect("Stack empty.") } fn add(&mut self) { self._do_binary_operation(|l, r| l + r); } fn subtract(&mut self) { self._do_binary_operation(|l, r| l - r); } fn multiply(&mut self) { self._do_binary_operation(|l, r| l * r); } fn divide(&mut self) { self._do_binary_operation(|l, r| l / r); } fn _do_binary_operation(&mut self, operation: |f64, f64| -> f64) { let r = self.numbers.pop().expect("Stack underflow."); let l = self.numbers.pop().expect("Stack underflow."); self.numbers.push(operation(l, r)); } } impl fmt::Show for Stack { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = String::new(); let mut i = self.numbers.len(); for number in self.numbers.iter() { i -= 1; s = s.add(&format!("{}: {}\n", i, number)); } s.pop_char(); write!(f, "{}", s) } } struct Tokenizer { tokens: Vec<String>, i: uint } impl Tokenizer { fn new(expression: &str) -> Tokenizer { Tokenizer{ tokens: expression.split(|c: char| c.is_whitespace()) .map(|s| s.to_string()) .collect(), i: 0 } } fn has_next_token(&self) -> bool { self.i < self.tokens.len() } fn next_token(&mut self) -> &str { if !self.has_next_token() { fail!("Tokens exhausted.") } let token = self.tokens[self.i].as_slice(); self.i += 1; token } } struct RPNCalculator { stack: Stack, tokens: Tokenizer } impl RPNCalculator { fn new(stack: Stack, tokens: Tokenizer) -> RPNCalculator { RPNCalculator{stack: stack, tokens: tokens} } fn calculate(&mut self) -> f64 { while self.tokens.has_next_token() { let token = self.tokens.next_token(); if !self.stack.is_empty() { println!("{}", self.stack); } println!("T: {}\n", token); match token { "+" => { self.stack.add(); } "-" => { self.stack.subtract(); } "*" => { self.stack.multiply(); } "/" => { self.stack.divide(); } n => { self.stack.push(from_str(n).expect("Not a number.")); } } } if !self.stack.is_empty() { println!("{}\n", self.stack); } self.stack.result() } } fn main() { let expression = os::args(); let stack = Stack::new(); let tokenizer = Tokenizer::new(expression[1].as_slice()); let mut calculator = RPNCalculator::new(stack, tokenizer); println!("{}", calculator.calculate()); }
-
1
APR
2012A Stylish Critique
Before getting started, I feel compelled to point out that my dictionary defines a critique as "a detailed analysis and assessment of something." It seems like we often assume the worst of that word, but that's not how I intend it here.
The Ruby community seems to be talking about style guides lately. So let's talk about them.
The fact is that you will have many choices if you go looking for style guides for our favorite language. You can pick from:
- The old stuff
- Google's way
- GitHub's popular guide
- Guides from respected Rubyists, like Dan Kubb
- One of the many forks of the popular guides on GitHub
- And many more
It's obvious that Rubyists care about this topic. Let's see what's out there and consider what really is and is not useful from these guides.
What is a style guide really, and why do we even have them?
Defining style guides is surprisingly tough. I suspect they started out as formatting rules for code, but they have evolved pretty far beyond that now.
Most guides include general conventions that the author feels are important when writing the language in question. This can go all the way down to how to use certain constructs, opinions on what the author considers idiomatic, and syntax to outright avoid.
-
8
OCT
2008Readable Booleans
There's a great little trick you can do to improve the readability of your code. A common problem is dealing with methods that have a boolean flag arguments. Here's an example I ran into just today in a Rails application:
def rating_stars(..., clickable = false) # ... end
The problem with this is that you typically see calls like this scattered around the application:
<%= rating_stars(..., true) %>
Would you know what
true
did there if I hadn't shown you the name of the variable first? I didn't. I had to go hunting for that method definition.Ironically the opposite problem, a magical dangling
false
, is much more rare in my experience. That's typically the default for these kind of arguments and it just makes more sense and reads better to leave it out.Anyway, the point is that we can typically improve the ease of understanding the common case. Remember that in Ruby
false
andnil
are false while everything else is true. That means that truth is very loosely defined and we can pass a lot of things for our boolean flag value. For example, after looking up the method and understanding what was needed, I chose to call it like this: -
7
OCT
2008DSL Block Styles
There's an argument that rages in the Ruby camps: to
instance_eval()
or not toinstance_eval()
. Most often this argument is triggered by DSL discussions where we tend to want code like:configurable.config do width 100 mode :wrap end
You can accomplish something like this by passing the block to
instance_eval()
and changingself
to an object that defines thewidth()
andmode()
methods. Of course changingself
is always dangerous. We may have already been inside an object and planning to use methods from that namespace:class MyObject include Configurable # to get the config() method shown above def initialize config do width calculate_width # a problem: may not work with instance_eval() end end private def calculate_width # the method we want to use # ... end end
In this example, if
width()
comes from a different configuration object, we're in trouble. Theinstance_eval()
will shift the focus away from ourMyObject
instance and we will get aNoMethodError
when we try to callcalculate_width()
. This may prevent us from being able to useConfigurable
in our code. -
13
JUN
2006Do I Need (These Parentheses()?)
If you came to Ruby via the Learn to Program book or just don't yet have a consistent set of rules for when you do and don't need parentheses in Ruby code, this post is for you.
I have nothing against Learn to Program, just to be clear. A member of my family is learning Ruby from it and it's going pretty well. I recommend it. However, Chris is a little inconsistent with his use of parentheses in the code samples, and worse, he doesn't really give you a good set of rules to decide when to make the choice. No problem. Let me give you the rules.
I'm a chess player. In learning chess, you really go through two phases. First, you learn the rules of strategy. These will make you good because the rules are designed to help you avoid common mistakes. Now, to get great, you go through the second phase: learning when to break the strategy rules. Ruby is exactly the same.
Here's the only rule of strategy you need to learn to get good: methods need parentheses around their arguments.