8
\$\begingroup\$

I wrote a short ruby script to generate various screenshots, and event though I am not completely new to ruby I rarely use it.

Full script (41 LOC): https://gist.github.com/1229115

The string substitutions irritate me. They don't look quite right - much too ugly for a beautiful and concise language like ruby. Am I overdoing it? What alternatives are there?

Here is the lines I am concerned about (for context, please take a look at the gist):

# assemble file name
fname = "#{directory}/#{prefix}-#{timestamp}-#{commit}-#{size[:width]}x#{size[:height]}.png"
# create command line stuff
call = "#{macruby_exe} #{snapper} \
 --width #{size[:width]} --height #{size[:height]} #{url} #{fname}"
# now call it
system call
# just to show the progress (and the file sizes)
puts "#{fname} (#{File.size?(fname) / 1024}kB)"

Just to illustrate the script, the output usually looks like:

screenies/screenshot-1316535022-0b5c7967887481deb17bcd9039cd3fe0ac4540d4-640x960.png (95kB)
screenies/screenshot-1316535022-0b5c7967887481deb17bcd9039cd3fe0ac4540d4-800x480.png (62kB)
screenies/screenshot-1316535022-0b5c7967887481deb17bcd9039cd3fe0ac4540d4-800x600.png (78kB)
 ^ ^ ^ ^ ^
 | | | | ________|______
 | | | | | |
directory prefix timestamp commit size[:width] x size[:height]
asked Sep 20, 2011 at 16:12
\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

There are other ways you could write this but I'm not sure if you'd find any of them cleaner. One option is plain old sprintf. For example:

# assemble file name
fname = sprintf("%s/%s-%i-%s-%ix%i.png", directory, prefix, timestamp,
 commit, size[:width], size[:height])

You could shorten it a little by giving size its own to_s method:

class << size; def to_s; "#{self[:width]}x#{self[:height]}" end end
fname = sprintf("%s/%s-%i-%s-%s.png", directory, prefix, timestamp,
 commit, size)

...and perhaps create other convenience methods along the same lines. But still, very small gains.

Another option would be to make your own super-small template engine, something like this:

def tiny_subst template, bndg
 param_exp = /:(\w+)[^\w:]+/i
 tmpl_params = template.scan(param_exp).flatten
 proc {
 out_str = template.clone
 tmpl_params.reduce(out_str) do |str, p|
 str.gsub ":#{p}", eval(p, bndg).to_s unless p.empty?
 end
 }
end
tmpl = ':directory/:prefix-:timestamp-:commit-:size.png'
subber = tiny_subst(tmpl, binding)
directory = 'screenies'
prefix = 'screenshot'
timestamp = Time.now.to_i
commit = '0b5c7967887481deb17bcd9039cd3fe0ac4540d4'
size = '640x960'
subber.yield # => screenies/screenshot-1316535022-0b5c7967887481deb17bcd9039cd3fe0ac4540d4-640x960.png
commit = 'foobarbazquux'
size = '9000x9000'
subber.yield # => screenies/screenshot-1316535022-foobarbazquux-9000x9000.png

So, that's kinda nice, but is it really worth it? Not for me, but I guess if you really hate "#{this}" it might be.

answered Sep 22, 2011 at 8:09
\$\endgroup\$
3
  • \$\begingroup\$ Thank you - an inspiring answer. I don't really hate #{this} but the mini-template seems nicer, I'll try it. \$\endgroup\$ Commented Sep 22, 2011 at 10:22
  • \$\begingroup\$ Well it's not really intended for use but if you find it useful I actually put it up on GitHub last night: github.com/jrunning/StupidLittleTemplate There are probably security implications to eval-ing variables in the local scope, so please don't use it in a production app, or at the very least sanitize user data until it sparkles before passing it in. \$\endgroup\$ Commented Sep 22, 2011 at 15:15
  • \$\begingroup\$ Great, I'll take a look. \$\endgroup\$ Commented Sep 23, 2011 at 12:28
2
\$\begingroup\$

Per your request (and drawing from your gist), more concise and readable is:

screensizes = [
# width height
 [ 640, 960 ], # iPhone 4
 [ 800, 480 ], # wvga
 [ 800, 600 ], # old school
 [ 1024, 600 ], # netbook, WSVGA
 [ 1024, 786 ], # old school, iPad
 [ 1200, 800 ], # macbook
 [ 1366, 786 ], # netbook
 [ 1440, 900 ], # macbook pro
 [ 1600, 768 ], # strange
 [ 1680, 1050 ], # hires macbok
]
screensizes.each do |w,h|
# Assemble file name:
 f = "#{directory}/#{prefix}-#{timestamp}-#{commit}-#{w}x#{h}.png"
# Create command line stuff:
 s = "#{macruby_exe} #{snapper} --width #{w} --height #{h} #{url} #{f}"
# Now call it:
 system s
# Show progress and file sizes:
 puts "#{f} (#{File.size?(f) / 1024}kB)"
end
answered Jan 21, 2012 at 23:56
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.