I have a question and perhaps a bit of challenge for those with mad
parse skills: Has anyone ever considered named parameters for sprintf/
printf? It would be quite useful (to me at least) to be able to do:
"I am %(name)s." % { :name => "Tom" ]
Has anyone worked on something like this before? Is there anything
equivalent in the Perl world or other language? I realize we can use
numerals to identify the substitutions, but I feel the labels are much
more readable. Moreover, ultimately it would be interesting to see:
"I am %(name)s." % binding
Making use of the binding's local_variables.
The challenge, of course, is to override printf/sprintf to do this
(the binding part gets you extra ruby points Even more
challenging, augment the C code to handle it and submit it as a patch.
I have a question and perhaps a bit of challenge for those with mad
parse skills: Has anyone ever considered named parameters for sprintf/
printf? It would be quite useful (to me at least) to be able to do:
"I am %(name)s." % { :name => "Tom" ]
Has anyone worked on something like this before? Is there anything
equivalent in the Perl world or other language? I realize we can use
numerals to identify the substitutions, but I feel the labels are much
more readable. Moreover, ultimately it would be interesting to see:
"I am %(name)s." % binding
Making use of the binding's local_variables.
The challenge, of course, is to override printf/sprintf to do this
(the binding part gets you extra ruby points Even more
challenging, augment the C code to handle it and submit it as a patch.
T.
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama
On Feb 28, 11:57 am, Trans <transf...@gmail.com> wrote:
I have a question and perhaps a bit of challenge for those with mad
parse skills: Has anyone ever considered named parameters for sprintf/
printf? It would be quite useful (to me at least) to be able to do:
"I am %(name)s." % { :name => "Tom" ]
Has anyone worked on something like this before? Is there anything
equivalent in the Perl world or other language? I realize we can use
numerals to identify the substitutions, but I feel the labels are much
more readable. Moreover, ultimately it would be interesting to see:
"I am %(name)s." % binding
Making use of the binding's local_variables.
The challenge, of course, is to override printf/sprintf to do this
(the binding part gets you extra ruby points Even more
challenging, augment the C code to handle it and submit it as a patch.
I released a gem last year (http://jig.rubyforge.com) that defines
a data structure I nicknamed a Jig that enables this sort of thing
either by parsing a string to get the format or by explicit
construction:
j = Jig.new('I am ', :name)
j2 = Jig.parse('I am %{:name:}')
puts j % { :name => 'Tom'} # I am Tom
puts j2 % { :name => 'Alice'} # I am Alice
A Jig is a ordered sequence of objects and 'gaps'. Simple gaps are
identified as symbols during Jig construction but you can also define
gaps that process anything that is used to fill them:
In that example you can see that all gaps with the same name
are plugged simultaneously. Unplugged gaps are rendered as
the empty string when Jig#to_s is called.
You can also construct a Jig or fill a gap with a proc/lambda/method
which will be evaluated at the time the Jig is rendered to a string:
time = Jig.new("The time is ") {Time.now}
puts time # The time is Thu Feb 28 18:16:07 -0500 2008
sleep 5
puts time # The time is Thu Feb 28 18:16:12 -0500 2008
The gem has classes for handling XML, XHTML, and CSS constructs.
I've made a few changes since the initialize release but haven't
gotten around to pushing it a new release to Rubyforge yet....
I have a question and perhaps a bit of challenge for those with mad
parse skills: Has anyone ever considered named parameters for sprintf/
printf? It would be quite useful (to me at least) to be able to do:
"I am %(name)s." % { :name => "Tom" ]
Has anyone worked on something like this before? Is there anything
equivalent in the Perl world or other language?
At Fri, 29 Feb 2008 01:57:23 +0900,
Trans wrote in [ruby-talk:292860]:
I have a question and perhaps a bit of challenge for those with mad
parse skills: Has anyone ever considered named parameters for sprintf/
printf? It would be quite useful (to me at least) to be able to do:
Yes, once I had posted the patch for it, and was rejected.
"I am %(name)s." % { :name => "Tom" ]
Has anyone worked on something like this before? Is there anything
equivalent in the Perl world or other language? I realize we can use
numerals to identify the substitutions, but I feel the labels are much
more readable. Moreover, ultimately it would be interesting to see:
"I am %(name)s." % binding
Making use of the binding's local_variables.
Though I don't feel it attractive, I believe named parameter is
an important feature for I18N, and IIRC, ruby-gettext has it.
Can you please explain this? It looks to me like it would allow you to
override a method, but still call the original without using alias.
However, when I try anything like that, it only calls the original
method. The method defined inside of M isn't called. Is that a 1.9
thing or am I misunderstanding what you meant?
···
On Feb 28, 11:29 am, ara howard <ara.t.how...@gmail.com> wrote:
class String
module M
def % *args
newstuff
super
end
end
include M
end
At Fri, 29 Feb 2008 01:57:23 +0900,
Trans wrote in [ruby-talk:292860]:
> I have a question and perhaps a bit of challenge for those with mad
> parse skills: Has anyone ever considered named parameters for sprintf/
> printf? It would be quite useful (to me at least) to be able to do:
Yes, once I had posted the patch for it, and was rejected.
> "I am %(name)s." % { :name => "Tom" ]
>
> Has anyone worked on something like this before? Is there anything
> equivalent in the Perl world or other language? I realize we can use
> numerals to identify the substitutions, but I feel the labels are much
> more readable. Moreover, ultimately it would be interesting to see:
>
> "I am %(name)s." % binding
>
> Making use of the binding's local_variables.
Though I don't feel it attractive, I believe named parameter is
an important feature for I18N, and IIRC, ruby-gettext has it.
You may find the recently announced Jig library of interest. I was sitting
next to Gary during something at RubyConf, maybe RejectConf, and he gave me
a demo. Pretty cool. See Subject: jig 0.1.2 Released - Ruby - Ruby-Forum
Nobu Nakada
--Greg
···
On Fri, Feb 29, 2008 at 01:51:02PM +0900, Nobuyoshi Nakada wrote:
At Fri, 29 Feb 2008 01:57:23 +0900,
Trans wrote in [ruby-talk:292860]:
> I have a question and perhaps a bit of challenge for those with mad
> parse skills: Has anyone ever considered named parameters for sprintf/
> printf? It would be quite useful (to me at least) to be able to do:
Yes, once I had posted the patch for it, and was rejected.
:(
> "I am %(name)s." % { :name => "Tom" ]
> Has anyone worked on something like this before? Is there anything
> equivalent in the Perl world or other language? I realize we can use
> numerals to identify the substitutions, but I feel the labels are much
> more readable. Moreover, ultimately it would be interesting to see:
> "I am %(name)s." % binding
> Making use of the binding's local_variables.
Though I don't feel it attractive, I believe named parameter is
an important feature for I18N, and IIRC, ruby-gettext has it.
Really? It seems like a nice way to apply parameter to templates to
me. Rather then, say,
xml = %{
<customer id="#{params[:id]}">
<name>#{params[:name]}</name>
</customer>
}
One could do:
xml = %{
<customer id="%(id)u">
<name>%(name)s</name>
</customer>
} % params
A little cleaner --and provides a nice means of reusable
interpolation.
I'll have to look at ruby-gettext.
Thanks,
T.
···
On Feb 28, 11:51 pm, Nobuyoshi Nakada <n...@ruby-lang.org> wrote:
> class String
> module M
> def % *args
> newstuff
> super
> end
> end
> include M
> end
>
However, when I try anything like that, it only calls the original
method. The method defined inside of M isn't called.
...
I also couldn't get Ara's example to work, so I resorted to monkeypatching.
(Yes, I know, I am Destroying Ruby..)
···
On 2/28/08, yermej <yermej@gmail.com> wrote:
On Feb 28, 11:29 am, ara howard <ara.t.how...@gmail.com> wrote:
----------
p "I am %s." % "string"
p "I am %s." % ["array"]
p "I am %s." % { :name => "hash" }
begin
p "I am %(name)s." % { :name => "hash" }
rescue ArgumentError => err
p "caught #{err}"
end
puts "\nMonkeyPatching!\n\n"
class String
alias :old_percent :%
def % arg
arr = (arg.kind_of? Array) ? arg : [arg]
target = self.gsub(/%\((.+?)\)/){|m|
raise ArgumentError, "named parameters need hash" unless arg.kind_of? Hash
arr << arg[$1.to_sym]
"%#{arr.size}$"
}
target.old_percent arr
end
end
p "I am %s." % "string"
p "I am %s." % ["array"]
p "I am %s." % { :name => "hash" }
p "I am %(name)s." % { :name => "hash" }
p "I am %(name)s %(with)s %(what)s"%{:what => "multiple arguments",
:with => "including", :name=> 'hash'}
p "I am %(name)s %(with)s %1$p"%{:with => "containing", :name=> 'hash'}
p "I am %(name)s." % [:name, "array"]
-Adam
P.S. It actually looks like patching sprintf wouldn't be too hard, as
long as you disallowed mixing named arguments with any other type.
No you are right. Including a module in a class effectively inserts
the module above the class in the inheritance chain rather than below,
a class can override methods in a module it includes, not the other
way around. I missed Ara's point as well.
Along these lines I was scratching my head the other night when I was
reading Russ Olsen's "Design Patterns in Ruby" and he was showing an
implementation of the Decorator pattern using modules as decorators, I
missed the subtlety that he was using Object#extend to include a
module above the singleton class of a particular object rather than
including it in a 'real' class. But I don't think that technique
applies here.
···
On 2/28/08, yermej <yermej@gmail.com> wrote:
On Feb 28, 11:29 am, ara howard <ara.t.how...@gmail.com> wrote:
> class String
> module M
> def % *args
> newstuff
> super
> end
> end
> include M
> end
>
Can you please explain this? It looks to me like it would allow you to
override a method, but still call the original without using alias.
However, when I try anything like that, it only calls the original
method. The method defined inside of M isn't called. Is that a 1.9
thing or am I misunderstanding what you meant?
def % *a, &b
a.flatten!
string =
case a.last
when Hash
expand a.pop
else
self
end
if a.empty?
string
else
Percent.bind(string).call(*a, &b)
end
end
def expand! vars = {}
loop do
changed = false
vars.each do |var, value|
var = var.to_s
var.gsub! %r/[^a-zA-Z0-9_]/, ''
[
%r/\$#{ var }\b/,
%r/\@#{ var }\b/,
%r/\$\{\s*#{ var }\s*\}/,
%r/\@\{\s*#{ var }\s*\}/,
].each do |pat|
changed = gsub! pat, "#{ value }"
end
end
break unless changed
end
self
end
def expand opts = {}
dup.expand! opts
end
end
puts( 'I am @name'.expand(:name => 'Ara') )
puts( 'I am @name' % {:name => 'Ara'} )
On Feb 28, 11:29 am, ara howard <ara.t.how...@gmail.com> wrote:
class String
module M
def % *args
newstuff
super
end
end
include M
end
Can you please explain this? It looks to me like it would allow you to
override a method, but still call the original without using alias.
However, when I try anything like that, it only calls the original
method. The method defined inside of M isn't called. Is that a 1.9
thing or am I misunderstanding what you meant?
--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama
I would like to add this to Facets, though under a slightly different
naming of course. Not sure what though #printfv#sprintfv ?
Thanks!
T.
···
On Feb 28, 3:42 pm, "Adam Shelly" <adam.she...@gmail.com> wrote:
On 2/28/08, yermej <yer...@gmail.com> wrote:
> On Feb 28, 11:29 am, ara howard <ara.t.how...@gmail.com> wrote:
> > class String
> > module M
> > def % *args
> > newstuff
> > super
> > end
> > end
> > include M
> > end
> However, when I try anything like that, it only calls the original
> method. The method defined inside of M isn't called.
...
I also couldn't get Ara's example to work, so I resorted to monkeypatching.
(Yes, I know, I am Destroying Ruby..)
----------
p "I am %s." % "string"
p "I am %s." % ["array"]
p "I am %s." % { :name => "hash" }
begin
p "I am %(name)s." % { :name => "hash" }
rescue ArgumentError => err
p "caught #{err}"
end
puts "\nMonkeyPatching!\n\n"
class String
alias :old_percent :%
def % arg
arr = (arg.kind_of? Array) ? arg : [arg]
target = self.gsub(/%\((.+?)\)/){|m|
raise ArgumentError, "named parameters need hash" unless arg.kind_of? Hash
arr << arg[$1.to_sym]
"%#{arr.size}$"
}
target.old_percent arr
end
end
p "I am %s." % "string"
p "I am %s." % ["array"]
p "I am %s." % { :name => "hash" }
p "I am %(name)s." % { :name => "hash" }
p "I am %(name)s %(with)s %(what)s"%{:what => "multiple arguments",
:with => "including", :name=> 'hash'}
p "I am %(name)s %(with)s %1$p"%{:with => "containing", :name=> 'hash'}
p "I am %(name)s." % [:name, "array"]
Hmmm... this looks more like an answer to the interpolation question
asked in a earlier thread. Is this a full-fledge implementation? Would
it be a better solution then:
def String.interpolate(&str)
eval "%{#{str.call}}", str.binding
end
T.
···
On Feb 28, 7:13 pm, ara howard <ara.t.how...@gmail.com> wrote:
On Feb 28, 2008, at 1:09 PM, yermej wrote:
> On Feb 28, 11:29 am, ara howard <ara.t.how...@gmail.com> wrote:
>> class String
>> module M
>> def % *args
>> newstuff
>> super
>> end
>> end
>> include M
>> end
> Can you please explain this? It looks to me like it would allow you to
> override a method, but still call the original without using alias.
> However, when I try anything like that, it only calls the original
> method. The method defined inside of M isn't called. Is that a 1.9
> thing or am I misunderstanding what you meant?
i was just being stupid. you'd need something like this
def % *a, &b
a.flatten!
string =
case a.last
when Hash
expand a.pop
else
self
end
if a.empty?
string
else
Percent.bind(string).call(*a, &b)
end
end
def expand! vars = {}
loop do
changed = false
vars.each do |var, value|
var = var.to_s
var.gsub! %r/[^a-zA-Z0-9_]/, ''
[
%r/\$#{ var }\b/,
%r/\@#{ var }\b/,
%r/\$\{\s*#{ var }\s*\}/,
%r/\@\{\s*#{ var }\s*\}/,
].each do |pat|
changed = gsub! pat, "#{ value }"
end
end
break unless changed
end
self
end
def expand opts = {}
dup.expand! opts
end
end
puts( 'I am @name'.expand(:name => 'Ara') )
puts( 'I am @name' % {:name => 'Ara'} )
puts "\nMonkeyPatching!\n\n"
class String
alias :old_percent :%
def % arg
arr = (arg.kind_of? Array) ? arg : [arg]
target = self.gsub(/%\((.+?)\)/){|m|
raise ArgumentError, "named parameters need hash" unless
arg.kind_of? Hash
arr << arg[$1.to_sym]
"%#{arr.size}$"
}
target.old_percent arr
end
end
<snip/>
Don't forget the escaped %, and also, I propose the format %foo:s
instead of %(foo)s. And heres some more code to chew on, based off of
Adam's:
class String
alias old_percent %
def % arg
names =
target = gsub /(^|[^%])%(\w+) do
name, space = $2, $1 # don't forget to replace whatever wasn't %
names << name unless names.include? name
"#{space}%#{names.rindex(name) + 1}$"
end
args = case arg
when Hash: names.map {|n| arg[n] or arg[n.to_sym]} #keys are often
symbols
when Array: arg
else [arg]
end
old_percent args
end
end