Episode 32: Time in Text Field

Posted about 1 year back at Railscasts

Although Rails does allow you to edit time attributes with text fields, it's not very flexible. In this episode you will learn how to use a virtual attribute to format the time to your liking.

RailsConf '07 and SF geekSessions

Posted about 1 year back at PJ Hyett

The Err Free team will be accepting beers at RailsConf for anyone interested, come find us.

Chris will be talking about his acts_as_cached plugin on Saturday. He promised me it’s gonna be good and he’s not one to disappoint.

Also, if you’re going to be in the Bay area after RailsConf, there’s a three hour session on the 22nd concerning whether Rails can scale.

It’s $15, has smart people talking, and there’s an open bar afterwards…need I say more? Check it out.

Off To RailsConf and @media America

Posted about 1 year back at danwebb.net - Home

Just breaking radio silence briefly to say that I’m off to the states (again) to speak at RailsConf in Portland 17th-20th then on to @media America in San Francisco for the 21st-28th. I’m going to be doing presentations both called ‘The Mysteries Of JavaScript-Fu’, both with an old skool kung fu theme but quite different aside from that. If you are around in either of these places or have any tips on good skate and sneaker stores then drop me a line….I’m always up for a couple of cold ones or/and sneaker shopping missions.

When I get I’ll be working a load more on Low Pro and blogging more about it. It’s developing quickly at the moment as Prototype picks up momentum and it’s getting some damn good features. In the meantime, you could always check out the trunk and see the new features that have already gone in. Build the trunk release then try as a sneak preview:

$('an_element').wrap('<strong>');

Also, look out for a major new set of features for Event Wax scheduled for release round about the time of @media London.

Semantic CSS and Rapid Development

Posted about 1 year back at Grinding Rails

Jonny LeRoy commented on my post about CSS style with a very astute observation.

Using classes like “float_left” (.float_left { float: left; }) breaks the separation of markup from presentation and makes it difficult to change layouts / looks just by switching stylesheets.

It’s an excellent point. In a follow up email, Jonny pointed me to this W3C tip. The essential point is that CSS class names should answer the question why and not how. A class named red says how something should look. A class named warning would answer why.

After listening to Hampton Catlin speak about Haml on the Ruby on Rails Podcast it really got me thinking about website documents as a DOM rather than a random string. Semantically meaningful CSS is an important element of a well constructed DOM.

Since I’m not a designer by trade, I approach UI work like programming. I do a lot of iterations and continuously distill XHTML to its most terse form. As an agile developer, I want to see results as quickly as possible. Early on this leads to very scary looking views. For example, a snippet from Wiffled:

<% for comment in @player.comments -%>
  <div style="border-bottom: 1px solid #ddd;">
    <p style="margin-top: 1em;">
    <% unless comment.sender.picture.nil? %>
      <%= image_tag comment.sender.picture.public_filename(:thumb), :style=>'float:left;margin-right: 1em' %>
    <% end -%>
  </div>
<% end -%>

Yuck! However, this is exactly how I work. I didn’t plan what I wanted the page to look like, I just wanted it to work. The best way to do this is to utilize the style attribute directly. This gives you the freedom to play around and try new things easily. Some might call it Rapid Development. I just call it GSD.

Of course if I left code in the above state, I wouldn’t be very good at my job. I believe it’s the next step that really separates web developers. Writing good models and controllers will get you straight up developer cred. But writing great views? That’s the specific domain of web developers.

Rails is really great at the M and C of MVC. ERB is nice, but it’s not a leap on par with the rest of Rails. The next big web app innovation will almost have to come in the View space. I highly suspect it will come from the Ruby community because a great view framework will require a lot of opinions. Semantic CSS and rapid development are some of the things I care about, but I’m sure you’ve got lots of concerns of your own.

By: Derek

Posted about 1 year back at Adam @ Bitscribe

just fyi, Ubuntu has the utility a2enmod for automagically creating those symlinks for you.

a2enmod rewrite
a2enmod proxy

also note a2dismod, a2ensite, a2dissite

Fun with hpricot

Posted about 1 year back at bleything.blog(:stuff)

Those who know me personally know that I’m a pretty huge video game nerd. I’ve been wanting to learn hpricot better, so I decided to combine the two interests. I give you vgdod.rb, which goes and scrapes info about Amazon Video Games’ Deal of the Day. It could probably be optimized, and the XPath could likely be better, but it gets the job done!

It was interesting to try to write XPath for HTML that I didn’t control… this was the first time I’ve had that particular joy, and it was a good exercise. I think we (web developers, that is) sometimes forget that other people might want to manipulate our HTML at some point. Anyway, the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env ruby

%w(rubygems hpricot open-uri shorturl).each {|g| require g}
def fetch(url = '') ; return Hpricot(open("http://www.amazon.com" + url)) ; end

vg_url = fetch.at("a[text()=Video Games]")[:href]
dotd_img = fetch(vg_url).search("img").select {|e| e[:src] =~ /deal-of-the-day/}.first
dotd = fetch(dotd_img.parent[:href])

# title -- platform -- price -- url
printf "%s -- %s -- %s -- %s",
  dotd.at("//div.buying//b.sans").inner_text.strip,
  dotd.search("//b.price").last.inner_text.strip,
  dotd.search("//div[@class=buying]")[3].inner_text.gsub(/(\&nbsp;|\s|Platform:)/, ''),
  WWW::ShortURL.shorten("http://www.amazon.com#{dotd_img.parent[:href]}")

Fun with hpricot

Posted about 1 year back at bleything.blog(:stuff)

Those who know me personally know that I’m a pretty huge video game nerd. I’ve been wanting to learn hpricot better, so I decided to combine the two interests. I give you vgdod.rb, which goes and scrapes info about Amazon Video Games’ Deal of the Day. It could probably be optimized, and the XPath could likely be better, but it gets the job done!

It was interesting to try to write XPath for HTML that I didn’t control… this was the first time I’ve had that particular joy, and it was a good exercise. I think we (web developers, that is) sometimes forget that other people might want to manipulate our HTML at some point. Anyway, the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env ruby

%w(rubygems hpricot open-uri shorturl).each {|g| require g}
def fetch(url = '') ; return Hpricot(open("http://www.amazon.com" + url)) ; end

vg_url = fetch.at("a[text()=Video Games]")[:href]
dotd_img = fetch(vg_url).search("img").select {|e| e[:src] =~ /deal-of-the-day/}.first
dotd = fetch(dotd_img.parent[:href])

# title -- platform -- price -- url
printf "%s -- %s -- %s -- %s",
  dotd.at("//div.buying//b.sans").inner_text.strip,
  dotd.search("//b.price").last.inner_text.strip,
  dotd.search("//div[@class=buying]")[3].inner_text.gsub(/(\&nbsp;|\s|Platform:)/, ''),
  WWW::ShortURL.shorten("http://www.amazon.com#{dotd_img.parent[:href]}")

Two Ruby Quirks

Posted about 1 year back at interblah.net - Home

I stumbled across two Ruby quirks that I'd never seen before. Can these perversions of syntax be put to good use? I hope so (cue evil laugh)!

First up, a special case for method arguments. What do you think this does:


hello:dave

Turns out that it looks for the method hello, and supplies the symbol :dave as the first argument. What's odd about that? Well, not only are there no parenthesis, but there's no space between the method name and the argument. But it works!

1
2
3
4
5
def hello(*args)
  puts args.inspect
end

hello:dave # ==> [:dave]

Weird!

Secondly, and more weirdly, what do you make of this:

1
2
3
4
5
class Hello
end

Hello::dave
# ==> undefined method 'dave' for Hello:Class

Note that we're using the double-colon now. Doing this with a lower-case right hand side (as opposed to the capitalized, constantesque Base in ActiveRecord::Base) will cause Ruby to attempt a call to a method defined on the class itself! It's the same as calling


Hello.dave

Does anyone else find this weird? I've been using Ruby basically full-time since around 2002, but I'd never seen these quirks before...

On a somewhat related note, it's possible to define a method that looks like a constant, and some people use this to create Java-style constructor calls:

1
2
3
4
5
6
7
8
9
10
class Hello
  def initialize(*args)
  end
end

def Hello(*args)
  Hello.new(*args)
end

Hello(:dave)  # ==> #<Hello:0x35233>

So we can now also add


Hello:dave

to our menagerie of odd Ruby syntaxes. I wouldn't really recommend it because it's not "The Ruby Way" and will look weird to anyone who doesn't know about your quirks, but it's fun to know. Actually, I believe _why employs this trick in Camping Routes...

Backup of Bloglines keep new items

Posted about 1 year back at Spejman On Rails

If you are a Bloglines user, you probably save the interesting posts using "keep new" feature.

If you have use this reader for a time, the quantity of post saved could be large... Some day I thought that won't be funny to loose all this data, then I build a ruby script to backup bloglines "keep new" items into a xml file.

With this script I learned better Mechanize and Hpricot Ruby libraries.
Este script me ha servido para probar dos librerías muy útiles de Ruby: mechanize y hpricot.

You need these libraries in order to use the script:


gem install json
gem install activesupport
gem install hpricot
gem install mechanize


And here you have the script. I think is very understandable. I hope it helps you to backup your bloglines account (remember to change EMAIL and PASSWORD values with yours) or to understand better how mechanize and hpricot works.

require "rubygems"
require "hpricot"
require "json"
require "mechanize"
require "active_support"

# Reads a bloglines javascript tree structure that has all
# feeds data.
def read_tree( tree_base, label = "" )
tree_base.each do |tree|
if tree["kids"]
read_tree tree["kids"], label + "/" + tree["n"]
else
@feeds << [tree["n"], label, tree["kn"], "http://www.bloglines.com/myblogs_display?sub=#{tree["id"]}&site=#{tree["sid"]}"]
end
end
end

# Add more memory to hpricot otherwise couldn't load some webs.
Hpricot.buffer_size = 262144

agent = WWW::Mechanize.new
page = agent.get 'http://www.bloglines.com/login'

form = page.forms[1]
form.email = 'EMAIL'
form.password = 'PASSWORD'

page = agent.submit form

# Get the bloglines sindicated feeds
menu_page = agent.get "http://www.bloglines.com/myblogs_subs"
start_text = "var initTreeData = "
end_text = "\n;\n"
js_feeds_tree_str = menu_page.content[menu_page.content.index(start_text)+start_text.size..menu_page.content.index(end_text)]
feeds_tree = JSON.parse js_feeds_tree_str.gsub("\\","")
@feeds = []
read_tree(feeds_tree["kids"])

puts "<bloglines_saves>"
@feeds.each do |feed|

page = agent.get feed[3]
doc= Hpricot(page.content)

# get the content of all saved feed posts
content = ((doc/"body")/"td.article")
next if content.empty?
puts "<feed name=\"#{feed[0].strip}\" folder=\"#{feed[1].strip}\">"

# Iterate each saved feed post
((doc/"body")/"a.bl_itemtitle").each_with_index do |title, index|
puts "<feed_save title=\"#{title.inner_html.strip}\" href=\"#{title.attributes["href"]}\">"
puts content[index].inner_html.to_xs
puts "</feed_save>"
end
puts "</feed>"

end
puts "</bloglines_saves>"

Más información:

Hampton Catlin - Ruby on Rails Podcast

Posted about 1 year back at Ruby on Rails Podcast

The author of HAML rants on markup, Macs, diversity, and tech writing.
Also mentioned

Hampton Catlin - Ruby on Rails Podcast

Posted about 1 year back at Ruby on Rails Podcast

The author of HAML rants on markup, Macs, diversity, and tech writing.
Also mentioned

(Un)Support for prepared statements in Ruby on Rails

Posted about 1 year back at 赖洪礼的 blog

One of the many security problems generally found in web applications is the so-called SQL injection bug. If one isn’t careful, then an attacker can make the web application execute arbitrary SQL statement. There are two ways to prevent SQL injection bugs:

  1. Escape input before putting it into the final SQL statement. Ruby on Rails will automatically do this for you in most cases.
  2. Use prepared statements. In this scheme, one sends a statement containing placeholders to the DBMS. Then one binds arguments to the placeholders. Finally, one executes the prepared statements (with the bound arguments). The second and third phase can be repeated indefinitely, thus reusing the same prepared statement. Here is an example in pseudo code:
    Ruby
    1. # The ‘?’ is a placeholder
    2. statement = db.prepare("SELECT * FROM foo WHERE bread = ? AND cake = ?")
    3.  
    4. # Binds the first ‘?’ to "foo", and the second ‘?’ to "no’ SQL injection possible", then
    5. # executes the statement. This has the same effect as running:
    6. #
    7. #    SELECT * FROM foo WHERE brad = ‘foo’ AND cake = ‘no\’ SQL injection possible’
    8. #
    9. # (Note that the string escape character is database-specific, this is only an example.)
    10. statement.execute("foo", "no’ SQL injection possible")
    11.  
    12. # We reuse the same prepared statement and execute it multiple times, with
    13. # different parameters.
    14. statement.execute("hello", "world")
    15. statement.execute("apple", "pear")
    16. statement.execute("a", "b")

    Using prepared statements is generally preferred. It looks better and one cannot forget to escape an argument. Many DBMSes will also compile and optimize prepared statements internally, so if you want to execute many similar statements, then using prepared statements will give you a performance boost. Databases like Oracle are heavily dependent on prepared statements, and will perform badly if you don’t use them.

Unforunately Ruby on Rails’s does not support prepared statements at all. People have blogged about this in the past. A quote from Greg Luck:

We have two production applications running on Ruby. And how is it. Well, despite being perhaps no more than 5% of the functionality of our applications, Ruby on Rails is the number one consumer of Oracle CPU and logical gets. Why? Rails does not support prepared statements, so Oracle has to reparse every time.

EDIT: someone told me that this has been fixed in Rails 1.2, by using the “cursor=similar” option or something.

This is a shame. Because it doesn’t only cause problems for the database, but also for Rails itself. If an argument is large (for example, a large binary blob), then Rails will use a lot of memory trying to escape the string. Some people have been bitten by this before. Using prepared statements will solve a lot of problems, so I began working on this.

How does ActiveRecord work right now?

Here is a diagram of ActiveRecord’s current architecture:
ActiveRecord’s current architecture
(SVG version)

A Rails application only interfaces with ActiveRecord::Base (and other public ActiveRecord classes). Internally, ActiveRecord::Base aggregates an AbstractAdapter object (in the connection field), which abstracts away database-specific code. An AbstractAdapter is an abstract class. For example, PostgreSQLAdapter is one of its child classes, and implements PostgreSQL support. Each AbstractAdapter, in turn, aggregates an ‘raw connection’ object, which is a Ruby class that directly interacts with the database server.
An AbstractAdapter implements multiple interfaces, such as DatabaseStatements (for executing database statements) and Quoting (for escaping arguments for use in an SQL statement). Each AbstractAdapter child class has a different implementation for these interfaces.

ActiveRecord::Base methods, such as find(), work by constructing an SQL query, which they then execute. For example, the find() method can be described in pseudo code, as follows:

Ruby
  1. def find(options)
  2.     sql = ""
  3.     # Appends "SELECT #{options[:select]} FROM #{table_name}" to _sql_
  4.     create_select(sql, options)
  5.     # Appends "WHERE a = ‘b’ AND c = ‘d’" to _sql_
  6.     create_condition(sql, options)
  7.     …
  8.     # Appends "GROUP BY #{options[:group]}" to _sql_
  9.     create_group_by(sql, options)
  10.  
  11.     # Now we have a full SQL statement.
  12.     return @connection.select_all(sql)
  13. end

If we look at create_condition(), we see something like this:

Ruby
  1. def create_condition(sql, options)
  2.     sql < < "WHERE #{sanitize_sql(options[:conditions])}"
  3. end

The sanitize_sql function is an important function ActiveRecord’s SQL statement building process. Its job is to bind parameters into a part of an SQL statement (and escaping strings where necessary). For example, all of these:

Ruby
  1. sanitize_sql(["a = ? AND b = ?", "hello", "world"])
  2. sanitize_sql(["a = %s AND b = %s", "hello", "world"])
  3. sanitize_sql({:a => "hello", b => "world"})

return “a = ‘hello’ AND b = ‘world’”.

Adding support for prepared statements

Most databases support prepared statements, but I have heard that not all do. Furthermore, some Ruby database modules have no support for prepared statements! Prior to version 0.7, the Ruby-PostgreSQL module doesn’t support prepared statements at all. So my design will have to take this into account.

The new architecture will look as follows:
ActiveRecord with prepared statements
I have introduced 3 new classes: StatementBuilder (an abstract base class), StandardStatementBuilder and PreparedStatementBuilder. StatementBuilder allows one to build an SQL statement incrementally, possibly with arguments. It is supposed to replace ActiveRecord::Base’s sanitize_sql() function.
StandardStatementBuilder is almost exactly the same as sanitize_sql, but in a different API. One can retrieve the final SQL statement (with bounded arguments) by calling statement().
PreparedStatementBuilder is similar, but saves the SQL statement (with placeholders) and the arguments in different fields. Separating the SQL statement and its arguments is required for database adapters that support prepared statements.

AbstractAdapter has gained a new method, new_statement(). This is a factory method which creates a new StatementBuilder. Depending on the specific AbstractAdapter child class (which may or may not support prepared statements), this method may create a StandardStatementBuilder, PreparedStatementBuilder, or some other StatementBuilder class. The default implementation of this method creates a StandardStatementBuilder, but MySQLAdapter will create a PreparedStatementBuilder if the underlying Ruby Mysql module supports prepared statements.

ActiveRecord::Base uses AbstractAdapter.new_connection() to create a StatementBuilder. It then uses that StatementBuilder object to build a complete SQL statement. Finally, it passes the StatementBuilder object to one of the DatabaseStatement methods for execution. Notice that the DatabaseStatement methods now accept both a StatementBuilder object and a String object. The latter is for backwards-compatibility.

The DatabaseStatement methods are implemented by the (concrete) AbstractAdapter child classes, so it goes without saying that the code for using StatementBuilder will go there.

Here’s an example in pseudo code which demonstrates StatementBuilder’s usage in ActiveRecord::Base:

Ruby
  1. def find(options)
  2.     statement = connection.new_statement(self.class.table_name)
  3.     create_select(statement, options)
  4.     create_condition(statement, options)
  5.     …
  6.     return @connection.select_all(statement)
  7. end
  8.  
  9. def create_condition(statement, options)
  10.     statement.add_fragment(options[:conditions])
  11. end

And MySQLAdapter’s execute() method (which executes an SQL statement) looks a bit like this:

Ruby
  1. def execute(statement)
  2.     if statement.is_a?(PreparedStatementBuilder)
  3.         st = @driver.prepare(statement.statement)
  4.         st.execute(*statement.arguments)
  5.         return st.result
  6.     else
  7.         # We call ‘to_s’ here because _statement_ can either be a StandardStatement
  8.         # or a String. This will ensure that we get the SQL statement string.
  9.         # StandardStatement.to_s() is an alias for statement()
  10.         return @driver.execute(statement.to_s)
  11.     end
  12. end

Incidentally, this architecture makes ActiveRecord::Base cleaner, since a lot of code has been moved to separate classes.

But where is the patch?

The patch isn’t finished yet. At the moment, only the MySQL adapter supports prepared statements. In ActiveRecord::Base, only the create() method uses StatementBuilder - everything else still builds SQL statements with sanitize_sql(). It passes all MySQL unit tests though.

I’m posting this story on my blog so that the Ruby on Rails core team can review my work, and see whether they accept this architecture. I’ve submitted an email to the rubyonrails-core mailing list.

I’m also working on prepared statements support in the PostgreSQL adapter, but unfortunately this adapter has many bugs, so it fails the unit tests even without my changes. There is a patch which fixes a lot of bugs in this adapter, and it’s two months old, but it hasn’t been applied or even reviewed yet. I can’t finish PostgreSQL support until this patch has been accepted.

FAQ

“Is there any reason why we *need* prepared statements?”

There is at least one such reason: handling binary data in select queries in PostgreSQL. In SELECT queries in ActiveRecord, binary strings cannot (”cannot”, not “are not”) be escaped properly, and the whole query fails. I was bitten by this 2 weeks ago, and it forced me to use non-binary columns.

“But am I to understand StatementBuilder code is going to
replace (cleanup) all the string hacks currently involved in building SQL
queries? Will the usage of prepared statements in MySQL/PostgreSQL become
implicit with this?”

The use of prepared statements in MySQL/PostgreSQL will
completely replace the argument escaping stuff. Database adapters that
don’t support prepared statements (or haven’t implemented support yet)
will silently fallback to argument escaping, as is done now.

“Will compiled prepared statements be reused?”

Yes, at least in the MySQL adapter. I wrote a cache class so that other adapters can easily implement caching of prepared statements. The cache has a maximum size and will remove items based on least-recently-used, similar to how some CPU caches work.
However, in MySQL, caching prepared statements doesn’t give you much of a performance boost. When running the ActiveRecord unit tests, the cache hit rate is 65%, but resulted in no noticeable performance boost (or loss).

“Will querying with prepared statements be slower?”

On Oracle, no, or so I have heard. Even if one doesn’t cache prepared statements, Oracle will be much faster.
On MySQL, yes. Running the ActiveRecord unit tests is approximately 40% slower when using prepared statements. However, I added an optimization to the MySQL adapter. It will fallback to not using prepared statements if it detects that no argument is larger than 32 KB. This way, I have entirely eliminted the performance penalty in the average case, while reducing Ruby memory usage in case one of the arguments is a large binary blob.

Capistrano Off the Beaten Path

Posted about 1 year back at Revolution On Rails

Introduction

If you use Capistrano, most likely you use it to deploy rails applications by running it from the project directory. The plugem management tool piggy-backs on Capistrano to execute some recipes without using the current path because recipes operate on gems. Recipes do not, however, completely ignore the current directory, but instead use it for optional customization. Customization is not limited to a deployment recipe from the current directory but can be environment-specific across multiple sites if they each have a special extension gem installed.

Background

We use a bunch of ruby scripts at RHG for deployment and delivery of our numerous applications and shared component. When we started preparing some of that functionality for a public release, we needed to provide a way to customize the scripts. Warren Konkel suggested to migrate them to Capistrano since it was the most familiar tool for rails developers and it has a recipes hierarchy that can be used for customization. So, we wrote the plugem command tool that feeds its parameters to Capistrano via Capistrano::CLI.new(plugem_converted_arguments).execute!
after loading its own recipes.

The Code

    1 module Capistrano
2 class Configuration
3
4 alias :standard_cap_load :load
5
6 def load(*args, &block)
7
8 standard_cap_load(*args, &block)
9
10 if args == ["standard"]
11
12 load_plugem_deploy_recipes(File.dirname(__FILE__) + '/../..')
13
14 begin
15 require 'plugems_deploy_ext'
16 load_plugem_deploy_recipes(PLUGEMS_DEPLOY_EXT_DIR) # Overriding from extensions
17 rescue Exception
18 # No extension is loaded
19 end
20
21 end
22
23 end
24
25 def load_plugem_deploy_recipes(dir)
26 Dir[File.join(dir, 'recipes', '*')].each { |f| standard_cap_load(f) }
27 end
28
29 end
30 end

Ignoring lines 14-19 for now, all it does is inject the plugem deployment gem recipes to Capistrano. They are now available for execution by Capistrano. So when I call plugem update my_app it is being translated to cap plugem_update -s plugem_name=my_app(we use the plugem_ namespace for tasks and variables to avoid clashing with standard recipes). Since loading of plugem recipes is purposely not handled via the -f flag of capistrano, the standard deployment recipes like config/deploy.rb are still being loaded.

Customization

The package is extending Capistrano but we wanted it to be customized too. For example, you might want to define your own list of gem servers to download gems from. Capistrano allows to define recipes per project, user, or host. The plugems_deploy takes it a step further and provides a way to customize it per deployment environment, which might contain many hosts. It does this by expecting an optional plugems_deploy_ext gem to be installed on a system (lines 14-19). If it finds the extension gem, it loads recipes from there overriding the default ones.


Conclusion

Capistrano is not only a great deployment tool, it can be used as a base of highly-customizable general purpose tools.

Tough love from Verizon

Posted about 1 year back at DABlog - Home

I don’t think you have to be a language snob to wince (and laugh) at the way advertisers misuse English. They’re protected, of course, by the myths that surround their profession. If they get their grammar wrong, or misuse an idiom, they must have some ingenious marketing reason for doing so—or so people are willing to asusme. In fact, I think what’s happening is that the lousiness of the American educational system is trickling up into the ranks of copy writers and copy editors and basically everyone in the chain of custody of commercials.

The one that got me writing this post is a Verizon radio ad, specifically an ad for Verizon’s phone/cable/Internet triple package. It features the usual fake testimonial sound-bites from actors pretending to be customers. That’s par for the course, until one of them says (and the stuff in square brackets is a paraphrase; the rest is verbatim):

“[Verizon gives you a great deal,] providing all three services and not pulling any punches.“

I love the image of a Verizon repair person coming to my door and slugging me in the jaw, as hard as he or she can. (I’d rather it not happen, but I love the image.) It is, of course, completely clear that the person who wrote that line has no idea what the expression “pulling a punch� actually means, and neither do the executives who paid to have the ad written. I surmise that they think it means “pulling a stunt�, so that not pulling any punches means you’re entirely honest. Or something. Who knows?

I suppose that if Coors can actually bring to market a product called “Artic [sic] Ice�, then Verizon can sleepwalk through the process of producing radio commercials. In fact, it doesn’t surprise me any more. I no longer expect the ostensible gatekeepers to know what they’re doing. They probably never did, but I do think it’s gotten worse. And funnier.

Talking about distributed Ruby at LRUG tonight

Posted about 1 year back at Beyond The Type - Home

Just a quick note to say that I'll be giving a talk at tonight's London Ruby Users group on distributed Ruby (and Rails.

More details on the event here


1 ... 470 471 472 473 474 ... 520