[ANN] parseargs-0.0.0

Discussion in 'Ruby' started by Ara.T.Howard, May 31, 2005.

  1. Ara.T.Howard

    Ara.T.Howard Guest

    URLS

    http://raa.ruby-lang.org/search.rhtml?search=parseargs
    http://codeforpeople.com/lib/ruby/parseargs

    ABOUT

    parseargs is a library that faciltates the parsing of arguments and keywords
    from method paramters, setting of default values, validation, contraints via
    class based or duck based typing, and coercion/convincing to type/ducktype
    when possible.


    HISTORY

    0.0.0

    initial version


    AUTHOR

    ara [dot] t [dot] howard [at] noaa [dot] gov

    SAMPLES

    <========< sample/a.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/a.rb

    require 'parseargs'
    include ParseArgs

    #
    # simple use will declare which required and optional arguments a method can
    # accept. default values may be specifed if a hash is given as the argument
    # specification. an exception is thrown if required arguments are not given at
    # method invocation.
    #

    def method(*a)
    pa =
    parseargs(a) {
    required_argument :a
    optional_argument :b => 2
    }

    puts "#{ pa.a }#{ pa.b }"
    end

    method 4

    ~ > ruby sample/a.rb

    42



    <========< sample/b.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/b.rb

    require 'parseargs'
    include ParseArgs

    #
    # keywords can be declared in exactly the same way, and can be given at
    # invocation as either strings or symbols. default values may also be named for
    # both arguments and keywords. note that a required keyword with a default
    # specified is really an optional keyword ;-)
    #

    def method(*a)
    pa =
    parseargs(a) {
    required_argument :a
    required_keyword :b, :default => 2
    optional_keyword :c
    }

    puts "#{ pa.a }#{ pa.b }"
    end

    method 4, 'b' => 2

    ~ > ruby sample/b.rb

    42



    <========< sample/c.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/c.rb

    require 'parseargs'
    include ParseArgs

    #
    # several abbreviations exist to make the declaration more compact.
    #

    def method(*a)
    pa =
    parseargs(a) {
    r_arg :a
    r_kw :b
    o_kw :c
    }

    if pa.c
    puts "#{ pa.c }"
    else
    puts "#{ pa.a }#{ pa.b }"
    end
    end

    method 4, :b => 2
    method 4, :b => 2, 'c' => 42

    ~ > ruby sample/c.rb

    42
    42



    <========< sample/d.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/d.rb

    require 'parseargs'
    include ParseArgs

    #
    # many keywords or arguments can be specified at once using a list
    #

    def method(*a)
    pa =
    parseargs(a) {
    r_arg 'req_arg'
    o_kw ('a'..'z').to_a
    }

    kw = pa.a ? pa.a : pa.z

    puts "#{ pa.req_arg }#{ kw }"
    end

    method 4, 'a' => 2
    method 4, 'z' => 2

    ~ > ruby sample/d.rb

    42
    42



    <========< sample/e.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/e.rb

    require 'parseargs'
    include ParseArgs

    #
    # a single, or list of types may be given and the argument of invocation must be
    # one of those types as reports by '==='
    #

    def method(*a)
    pa =
    parseargs(a) {
    req_arg 'number', 'types' => [Float, Fixnum]
    }

    p pa.number
    end

    method 42
    method 42.0
    method '42.0'

    ~ > ruby sample/e.rb

    42
    42.0
    ./lib/parseargs.rb:112:in `value=': value given not of type(Float,Fixnum) in 'number=' (TypeError)
    from ./lib/parseargs.rb:296:in `parse'
    from ./lib/parseargs.rb:291:in `each'
    from ./lib/parseargs.rb:291:in `parse'
    from ./lib/parseargs.rb:393:in `parseargs'
    from ./lib/parseargs.rb:376:in `parseargs'
    from sample/e.rb:11:in `method'
    from sample/e.rb:20



    <========< sample/f.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/f.rb

    require 'parseargs'
    include ParseArgs

    #
    # failure of an argument to match a given type will cause coercion to be applied
    # if specified. the coerce argument may be either a method name or a proc that
    # receives the obj to be coerced. in either case the return value is used as
    # the new argument.
    #

    def method(*a)
    pa =
    parseargs(a) {
    arg :a, :types => Fixnum, :coerce => 'to_i'
    kw :b, :types => Fixnum, :coerce => lambda{|obj| obj.to_i}
    }

    p [pa.a, pa.b]
    end

    method 4, :b => 2
    method '4', :b => '2'

    ~ > ruby sample/f.rb

    [4, 2]
    [4, 2]



    <========< sample/g.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/g.rb

    require 'parseargs'
    include ParseArgs

    #
    # ducktyping is supported as a method name, or list of method names - all of
    # which an argument must respond_to? in order for an exception not to be thrown.
    # this is a very simple ducktype signature.
    #

    def method(*a)
    pa =
    parseargs(a) {
    r_arg 'string', 'ducktype' => [:upcase, :downcase]
    }

    puts pa.string.upcase.downcase
    end

    method ['42']

    ~ > ruby sample/g.rb

    42



    <========< sample/h.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/h.rb

    require 'parseargs'
    include ParseArgs

    #
    # a kind of ducktype 'coercion' - somthing i'm calling 'convincing' - may be
    # applied in order to convince an object that it really can play a certain role.
    # an argument may be 'convinced' via a module, which will be used to extend the
    # object on the fly, or a block which is passed the object and expected to
    # modify it's singleton class in such a way as to allow the object to become a
    # valid argument
    #

    module M
    def quack
    2
    end
    end

    def method(*a)
    pa =
    parseargs(a) {
    ra 'a', 'ducktype' => :quack,
    'convince' => lambda{|obj| class << obj; def quack; 4; end; end}

    ra 'b', 'ducktype' => :quack,
    'convince' => M
    }

    puts "#{ pa.a.quack }#{ pa.b.quack }"
    end

    method 'any ol', 'objects'

    ~ > ruby sample/h.rb

    42



    <========< sample/i.rb >========>

    ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/i.rb

    require 'parseargs'

    #
    # of course all this would be kind of silly for the simple cases shown - but it
    # can become very powerful as a form of meta-programming aid or when many
    # kewords are to be supported
    #

    class Command
    include ParseArgs

    KEYWORDS = %w(
    verbose
    quiet
    log
    help
    info
    force
    recursive
    stdin
    stdout
    stderr
    )

    PARSER =
    ParseArgs::parser::new {
    KEYWORDS.each{|kw| optional_keyword kw}
    }

    def initialize cmd
    @cmd = cmd
    end

    def execute(*argv)
    opts = PARSER.parse argv
    p @cmd => opts.select{|k,v| not v.nil?}
    end

    def background(*argv)
    opts = PARSER.parse argv
    p @cmd => opts.select{|k,v| not v.nil?}
    end

    end


    foo = Command::new 'foo.exe'
    foo.execute 'verbose' => true, 'stdin' => 'input.txt'
    bar = Command::new 'bar.exe'
    bar.execute 'verbose' => false, 'stdout' => 'output.txt'

    ~ > ruby sample/i.rb

    {"foo.exe"=>[["stdin", "input.txt"], ["verbose", true]]}
    {"bar.exe"=>[["stdout", "output.txt"], ["verbose", false]]}



    CAVEATS

    this library is experimental.


    enjoy.

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    Ara.T.Howard, May 31, 2005
    #1
    1. Advertising

  2. Ara.T.Howard

    Hal Fulton Guest

    Ara.T.Howard wrote:
    >
    > ABOUT
    >
    > parseargs is a library that faciltates the parsing of arguments and
    > keywords
    > from method paramters, setting of default values, validation,
    > contraints via
    > class based or duck based typing, and coercion/convincing to
    > type/ducktype
    > when possible.


    Interesting. I look forward to checking this out.

    >
    > HISTORY
    >
    > 0.0.0


    Hmm, I think I used a prior version of it... ;)


    Hal
     
    Hal Fulton, Jun 1, 2005
    #2
    1. Advertising

  3. Hal Fulton wrote:
    > Ara.T.Howard wrote:
    >> HISTORY
    >>
    >> 0.0.0

    >
    >
    > Hmm, I think I used a prior version of it... ;)


    Was that 0.0.0.0, or 0.0.0.0.0? ;)

    Ruby folks are so conservative in version numbering that it wouldn't be
    surprising to see negative versions... "Your library looks nice, but I'm
    not going to use use it until it goes positive."
     
    Joel VanderWerf, Jun 1, 2005
    #3
  4. Ara.T.Howard

    Ara.T.Howard Guest

    On Wed, 1 Jun 2005, Hal Fulton wrote:

    > Interesting. I look forward to checking this out.


    i'd love some feedback. i end up writing the code the library contains plenty
    so it seemed like a good candidate for a general purpose lib.

    >
    >>
    >> HISTORY
    >>
    >> 0.0.0

    >
    > Hmm, I think I used a prior version of it... ;)


    lol. ;-)

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    Ara.T.Howard, Jun 1, 2005
    #4
  5. Ara.T.Howard

    Ara.T.Howard Guest

    library versioning [WAS] Re: [ANN] parseargs-0.0.0

    On Wed, 1 Jun 2005, Joel VanderWerf wrote:

    > Hal Fulton wrote:
    >> Ara.T.Howard wrote:
    >>> HISTORY
    >>>
    >>> 0.0.0

    >>
    >>
    >> Hmm, I think I used a prior version of it... ;)

    >
    > Was that 0.0.0.0, or 0.0.0.0.0? ;)
    >
    > Ruby folks are so conservative in version numbering that it wouldn't be
    > surprising to see negative versions... "Your library looks nice, but I'm not
    > going to use use it until it goes positive."


    i use the libtool/ld versioning system:

    interface.implementation.age

    the first two are pretty self explanatory, the age bit need examples to
    explain.

    first of all, interface - age > 0 demonstrates backwards compatibility. so
    a lib like

    3.0.2

    supports interfaces

    3
    2
    1

    but NOT interface zero. a lib like

    7.4.2

    supports interfaces

    7
    6
    5

    and so on.

    the idea is that if you are using somethign arrayfields 3.4.0 in your code
    alot and see the version bump up to 3.5.0 you will know that only the
    implementation, not the interface, to the code has changed and can upgrade
    with some confidence. if, however, you saw the version go from 3.4.0 to 4.0.1
    you know that the interface has changed and you should upgrade with caution.
    an interface change might be something major like changing a method signature
    or name, or it could be something minor like adding a new method (but all olds
    one stay the same) - in either case the version gives you certain hints.

    i'd be curious to know the rational behind other ruby project's version
    numbers and what information can be gleaned from them.

    for mor about the versioning i use see

    http://codeforpeople.com/lib/ruby/library/library-0.0.0/doc/

    cheers.

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    Ara.T.Howard, Jun 1, 2005
    #5
  6. Ara.T.Howard

    Zev Blut Guest

    binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    Hello,

    This looks like a nice tool!
    Looking at your samples made me think about a few interesting details
    about Ruby. To start the discussion, below is your posted (a.rb)
    sample:

    On Wed, 01 Jun 2005 00:20:25 +0900, Ara.T.Howard <>
    wrote:

    > def method(*a)
    > pa =
    > parseargs(a) {
    > required_argument :a
    > optional_argument :b => 2
    > }
    >
    > puts "#{ pa.a }#{ pa.b }"
    > end
    >
    > method 4
    >
    > ~ > ruby sample/a.rb
    >
    > 42


    This looks like a fairly reasonable API, but one thing really struck
    me was that your variables needed to be referenced with the pa
    instance. This is understandable, but I kind of feel that if I were
    to use this API a lot I would really rather have parseargs just go
    ahead and set the variables in the current method's binding. Thus I
    can just reference a and b without the need to use pa.

    I was going to post a patch to your code, but decided it might be
    better to flesh out this idea. Below is some sample code that will
    display how I implemented a simple example of how you could remove the
    need to reference pa.

    ------
    def parse_data_hash(data, bd = binding)
    data.each do |k,v|
    vid = v.object_id
    eval("#{k.to_s} = ObjectSpace._id2ref(#{vid})", bd)
    end
    end

    def parse_test(data_hash)
    parse_data_hash(data_hash)
    puts local_variables.join(",")

    puts "Explicit binding passed"
    parse_data_hash(data_hash, binding)
    puts local_variables
    local_variables.each do |k|
    print "#{k} => "
    eval("print #{k}.inspect")
    puts
    end
    end

    parse_test({:a => [1,2,3], :b => "hello"})
    ------

    Writing this brought out a few really interesting details about Ruby
    that I would like to discuss.

    1) I had to use ObjectSpace._id2ref in order to achieve the ability to
    set variable a to the passed Array. I did not like using this method,
    even without the warning not to use it found in the "Ruby in a
    Nutshell" book. Interestingly this warning is not found in the RDoc
    and ri generated description. Is there a better way to do this?

    2) In parse_data_hash I attempted to make passing the binding
    optional. As you see in the parse_test that does not work, because it
    is assigning the binding to the binding of the parse_data_hash method
    and not from its' caller.

    2.1 ) eval currently makes passing the binding optional. Is there a
    way to do this in Ruby or is this something only available to the
    internal implementation?

    2.2) I was thinking it might be interesting if you could get the
    binding of the caller from calling "caller". Of course, having this
    ability opens your self up to a lot of dangerous usages and possibly
    some powerful usages too. One usage would be a way to get the binding
    of the caller for parse_data_hash. I am wondering if this is a bad
    idea and if any other languages allow you to do this?

    2.3) Does anyone have an example of how you can use eval with a Proc
    object instead of an binding? The docs say you can do this, but does
    not provide an example and my test below does not work either..

    ----
    p = Proc.new { x = "Hello" }
    eval("puts x", p)
    t.rb:1: undefined local variable or method `x' for main:Object (NameError)
    from t.rb:1
    ----


    I have some other fuzzy ideas about the binding and method objects,
    but I better save that for another day when I can unfuzz them.
    Although, one quick idea is if it would be possible in the future to
    save the binding to disk or send it to another Ruby process?


    Cheers,
    Zev Blut
     
    Zev Blut, Jun 1, 2005
    #6
  7. Joel VanderWerf wrote:
    > Hal Fulton wrote:
    >
    >> Ara.T.Howard wrote:
    >>
    >>> HISTORY
    >>>
    >>> 0.0.0

    >>
    >> Hmm, I think I used a prior version of it... ;)

    >
    > Was that 0.0.0.0, or 0.0.0.0.0? ;)
    >
    > Ruby folks are so conservative in version numbering that it wouldn't be
    > surprising to see negative versions... "Your library looks nice, but I'm
    > not going to use use it until it goes positive."


    And the version numbers of ideas (read: vapour ware) might well be
    imaginary numbers....
    "I' won't think about using it, before it becomes real." :)


    Happy rubying

    Stephan
     
    Stephan Kämper, Jun 1, 2005
    #7
  8. Ara.T.Howard

    Jim Weirich Guest

    Re: library versioning [WAS] Re: [ANN] parseargs-0.0.0

    On Tuesday 31 May 2005 11:16 pm, Ara.T.Howard wrote:
    > i use the libtool/ld versioning system:
    >
    >    interface.implementation.age
    >
    > the first two are pretty self explanatory, the age bit need examples to
    > explain.


    I hadn't seen age used like that before. Interesting.

    > i'd be curious to know the rational behind other ruby project's version
    > numbers and what information can be gleaned from them.


    The recommended RubyGems versioning policy is summarized at
    http://docs.rubygems.org/read/chapter/7. The main purpose of the policy is
    to allow reasonable version comparisons for dependency declarations,
    especially the use of the "approximately greater than" version operator (see
    http://docs.rubygems.org/read/chapter/16#page76)

    The libtool/ld policy would work gems as well, except that RubyGems wouldn't
    know the fine distinctions provided by the age field.

    --
    -- Jim Weirich http://onestepback.org
    -----------------------------------------------------------------
    "Beware of bugs in the above code; I have only proved it correct,
    not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
     
    Jim Weirich, Jun 1, 2005
    #8
  9. Ara.T.Howard

    Ara.T.Howard Guest

    Re: binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    On Wed, 1 Jun 2005, Zev Blut wrote:

    > Hello,
    >
    > This looks like a nice tool! Looking at your samples made me think about a
    > few interesting details about Ruby. To start the discussion, below is your
    > posted (a.rb) sample:
    >
    > On Wed, 01 Jun 2005 00:20:25 +0900, Ara.T.Howard <>
    > wrote:
    >
    >> def method(*a)
    >> pa =
    >> parseargs(a) {
    >> required_argument :a
    >> optional_argument :b => 2
    >> }
    >>
    >> puts "#{ pa.a }#{ pa.b }"
    >> end
    >>
    >> method 4
    >>
    >> ~ > ruby sample/a.rb
    >>
    >> 42

    >
    > This looks like a fairly reasonable API, but one thing really struck me was
    > that your variables needed to be referenced with the pa instance. This is
    > understandable, but I kind of feel that if I were to use this API a lot I
    > would really rather have parseargs just go ahead and set the variables in
    > the current method's binding. Thus I can just reference a and b without the
    > need to use pa.
    >
    > I was going to post a patch to your code, but decided it might be better to
    > flesh out this idea. Below is some sample code that will display how I
    > implemented a simple example of how you could remove the need to reference
    > pa.
    >
    > ------
    > def parse_data_hash(data, bd = binding)
    > data.each do |k,v|
    > vid = v.object_id
    > eval("#{k.to_s} = ObjectSpace._id2ref(#{vid})", bd)
    > end
    > end
    >
    > def parse_test(data_hash)
    > parse_data_hash(data_hash)
    > puts local_variables.join(",")
    >
    > puts "Explicit binding passed"
    > parse_data_hash(data_hash, binding)
    > puts local_variables
    > local_variables.each do |k|
    > print "#{k} => "
    > eval("print #{k}.inspect")
    > puts
    > end
    > end
    >
    > parse_test({:a => [1,2,3], :b => "hello"})
    > ------


    the problem here is that the variables will only be __available__ through eval
    either. eg. you'd have to

    p 'eval a'

    and could never

    p a

    i seem to recall a way of working around this but can't remember the thread...
    if i can figure it out i'll add this feature. currently parsearges supports
    an undoccumented feature, if you

    parseargs(argv => receiver) {
    arg 'a'
    kw 'b'
    }

    then receiver will be used to 'receive' the arguments. this works by

    begin
    receiver.send '[]=', name, value
    rescue NoMethodError
    begin
    receiver.send "#{ name }=", value
    rescue NoMethodError
    receiver.send "#{ name }", value
    end
    end

    eg. any object that responds_to? []=, #{name}=, or #{name} can be used.
    examples would be

    parseargs(argv => a_hash) {
    arg 'a'
    kw 'b'
    }

    or

    parseargs(argv => a_open_struct) {
    arg 'a'
    kw 'b'
    }

    and those objects will be parsed 'into'. this means that, if a way can be
    found to 'set the variable a, given the string "a", in the current scope' i
    could have the following work fine

    parseargs(argv => binding) {
    arg 'a'
    kw 'b'
    }

    p a
    p b

    to accomplish what you want.

    so. how can one do this??

    eval 'a = 42'
    p a

    i don't know how...

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    Ara.T.Howard, Jun 1, 2005
    #9
  10. Ara.T.Howard

    Ara.T.Howard Guest

    Re: library versioning [WAS] Re: [ANN] parseargs-0.0.0

    --8323328-1506942782-1117658085=:5787
    Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-1506942782-1117658085=:5787"

    This message is in MIME format. The first part should be readable text,
    while the remaining parts are likely unreadable without MIME-aware tools.

    --8323328-1506942782-1117658085=:5787
    Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
    Content-Transfer-Encoding: QUOTED-PRINTABLE

    On Wed, 1 Jun 2005, Jim Weirich wrote:

    > On Tuesday 31 May 2005 11:16 pm, Ara.T.Howard wrote:
    >> i use the libtool/ld versioning system:
    >>
    >> =A0 =A0interface.implementation.age
    >>
    >> the first two are pretty self explanatory, the age bit need examples to
    >> explain.

    >
    > I hadn't seen age used like that before. Interesting.
    >
    >> i'd be curious to know the rational behind other ruby project's version
    >> numbers and what information can be gleaned from them.

    >
    > The recommended RubyGems versioning policy is summarized at
    > http://docs.rubygems.org/read/chapter/7. The main purpose of the policy =

    is
    > to allow reasonable version comparisons for dependency declarations,
    > especially the use of the "approximately greater than" version operator (=

    see
    > http://docs.rubygems.org/read/chapter/16#page76)
    >
    > The libtool/ld policy would work gems as well, except that RubyGems would=

    n't
    > know the fine distinctions provided by the age field.


    thanks for the input jim. i dunno about switching all my libs though ;-( =
    the
    age thing is really handy so that applications can say "give me the more
    recent version that supports my interface" and end up getting v17.2.16 even=
    if
    the initial application was built against v3.2.2. on the other hand there =
    is
    no ruby 'linker' other than require_gem so maybe i ought to convert...

    cheers.

    -a
    --=20
    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    =3D=3D=3D=3D
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
    =3D=3D=3D=3D

    --8323328-1506942782-1117658085=:5787--
    --8323328-1506942782-1117658085=:5787--
     
    Ara.T.Howard, Jun 1, 2005
    #10
  11. Ara.T.Howard

    Zev Blut Guest

    Re: binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    Hello,

    On Thu, 02 Jun 2005 05:30:28 +0900, Ara.T.Howard <>
    wrote:

    > the problem here is that the variables will only be __available__
    > through eval
    > either. eg. you'd have to
    >
    > p 'eval a'
    >
    > and could never
    >
    > p a
    >
    > i seem to recall a way of working around this but can't remember the
    > thread...
    > if i can figure it out i'll add this feature.


    Wow I am quite surprised at this! It is quite odd that adding a
    variable through the use of eval, makes the variable appear in the
    local_variables method, but that you cannot access the variable unless
    you use eval... Below is a simpler example showing how using eval
    modifies the the local_variables response.

    ----------------------------------------------------------------------
    puts "[" + local_variables.join(" , ") + "]"
    #=> []
    eval 'a = 42'
    puts "[" + local_variables.join(" , ") + "]"
    #=> [a]
    puts a
    #=> undefined local variable or method `a' for main:Object (NameError)
    ----------------------------------------------------------------------

    If you cannot access a in your binding, why would eval add a to the
    local_variables? Can anyone explain this? I would like to know.

    Thanks,
    Zev Blut
     
    Zev Blut, Jun 2, 2005
    #11
  12. Ara.T.Howard

    Glenn Parker Guest

    Re: binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    Zev Blut wrote:
    >
    > If you cannot access a in your binding, why would eval add a to the
    > local_variables? Can anyone explain this? I would like to know.


    It is a curious side effect of the way Ruby is interpreted. Perhaps it
    is a performance optimization? It doesn't really have to be this way,
    but it won't affect you (much) in practical terms.

    Variables that are "visible" when a method is compiled are added to a
    table somewhere in the AST, and only those variables can be accessed
    directly in that method. Clearly, this table is not the same one that
    "eval" consults so we have, to put it diplomatically, a little
    disconnect. Eval can find the variable when asked, but the interpreter
    simply refuses to go looking for it in the first place.

    Now, ask yourself if you really care. Are you going to be writing code
    where you know the name of a variable ahead of time, but only initialize
    it inside an eval statement? If so, there are two simple workarounds:

    1. Initialize the variable before the eval.

    x = nil # make "x" visible beforehand
    eval "x = 1"
    print "#{x}\n"

    2. Assign the eval-initialized variable to a "visible" variable.

    eval "y = 2"
    y = eval "y" # make "y" visible afterwards
    print "#{y}\n"

    --
    Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/>
     
    Glenn Parker, Jun 2, 2005
    #12
  13. Ara.T.Howard

    Jim Weirich Guest

    Re: binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    Glenn Parker said:
    > 2. Assign the eval-initialized variable to a "visible" variable.
    >
    > eval "y = 2"
    > y = eval "y" # make "y" visible afterwards
    > print "#{y}\n"


    Actually, you don't even have to actually assign anything to y, you just
    need to make sure that the Ruby interpreter sees an assignment to y before
    the print. It's a subtle distinction, but consider the following code:

    eval "y = 2"
    y = 0 if false
    puts y # => 2 (not 0)

    --
    -- Jim Weirich http://onestepback.org
    -----------------------------------------------------------------
    "Beware of bugs in the above code; I have only proved it correct,
    not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
     
    Jim Weirich, Jun 2, 2005
    #13
  14. Ara.T.Howard

    Glenn Parker Guest

    Re: binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    Jim Weirich wrote:
    > Actually, you don't even have to actually assign anything to y, you just
    > need to make sure that the Ruby interpreter sees an assignment to y before
    > the print. It's a subtle distinction, but consider the following code:
    >
    > eval "y = 2"
    > y = 0 if false
    > puts y # => 2 (not 0)


    OK, but you have to admit that "y = 0 if false" is Dark Magic. Who is
    going to understand what is going on there? An optimizing interpreter
    might justifiably toss the entire statement.

    --
    Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/>
     
    Glenn Parker, Jun 2, 2005
    #14
  15. Ara.T.Howard

    Ara.T.Howard Guest

    how to create a variable with eval - solved! [WAS] Re: binding,

    On Thu, 2 Jun 2005, Zev Blut wrote:

    > Hello,
    >
    > On Thu, 02 Jun 2005 05:30:28 +0900, Ara.T.Howard <>
    > wrote:
    >
    >> the problem here is that the variables will only be __available__ through
    >> eval
    >> either. eg. you'd have to
    >>
    >> p 'eval a'
    >>
    >> and could never
    >>
    >> p a
    >>
    >> i seem to recall a way of working around this but can't remember the
    >> thread...
    >> if i can figure it out i'll add this feature.


    > Wow I am quite surprised at this!


    everyone is! ;-)

    > It is quite odd that adding a variable through the use of eval, makes the
    > variable appear in the local_variables method, but that you cannot access
    > the variable unless you use eval... Below is a simpler example showing how
    > using eval modifies the the local_variables response.
    >
    > ----------------------------------------------------------------------
    > puts "[" + local_variables.join(" , ") + "]"
    > #=> []
    > eval 'a = 42'
    > puts "[" + local_variables.join(" , ") + "]"
    > #=> [a]
    > puts a
    > #=> undefined local variable or method `a' for main:Object (NameError)
    > ----------------------------------------------------------------------
    >
    > If you cannot access a in your binding, why would eval add a to the
    > local_variables? Can anyone explain this? I would like to know.


    i didn't know about that, but it suggests a way to rig method_missing in
    Object to make it __seem__ like a variable has been created in scope:

    for example:

    harp:~ > cat a.rb
    require 'binding_of_caller'

    class Object
    def create_var name, env = nil
    Binding::eek:f_caller do |bnd|
    eval("#{ name }=nil", env || bnd)
    end
    end
    def set_var name, value, env = nil
    Binding::eek:f_caller do |bnd|
    eval("#{ name }=ObjectSpace::_id2ref(#{ value.object_id })", env || bnd)
    end
    end
    def get_var name, env = nil
    Binding::eek:f_caller do |bnd|
    eval("#{ name }", env || bnd)
    end
    end
    alias __method_missing__ method_missing
    def method_missing(m,*a,&b)
    Binding::eek:f_caller do |bnd|
    lv = eval 'local_variables', bnd
    name = m.to_s
    if lv.include? name
    return(get_var(name, bnd))
    else
    __method_missing__(m,*a,&b)
    end
    end
    end
    end

    set_var 'a', 42
    p a

    harp:~ > ruby a.rb
    42


    wow! it __can__ be done. now someone try to break it please! ;-)

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    Ara.T.Howard, Jun 2, 2005
    #15
  16. Ara.T.Howard

    Jim Weirich Guest

    Re: binding, ObjectSpace._id2ref [WAS] Re: [ANN] parseargs-0.0.0

    Glenn Parker said:
    > OK, but you have to admit that "y = 0 if false" is Dark Magic. Who is
    > going to understand what is going on there? An optimizing interpreter
    > might justifiably toss the entire statement.


    No argument ... I wasn't offering it as a coding practice, but as a
    demonstration that it is the presence of the "y=something" at compile
    time, as opposed to the execution of the statement at runtime, that makes
    the difference.

    --
    -- Jim Weirich http://onestepback.org
    -----------------------------------------------------------------
    "Beware of bugs in the above code; I have only proved it correct,
    not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
     
    Jim Weirich, Jun 2, 2005
    #16
  17. Ara.T.Howard

    Pit Capitain Guest

    Re: how to create a variable with eval - solved! [WAS] Re: binding,

    Ara.T.Howard schrieb:
    > wow! it __can__ be done. now someone try to break it please! ;-)


    Ask and thou shalt receive:

    > (previous code)


    def a; "ouch"; end

    > set_var 'a', 42
    > p a


    You get a name clash between methods and local variables. Otherwise,
    your code should work fine, AFAIKT.

    Regards,
    Pit
     
    Pit Capitain, Jun 2, 2005
    #17
  18. Ara.T.Howard

    Ara.T.Howard Guest

    Re: how to create a variable with eval - solved! [WAS] Re: binding,

    On Fri, 3 Jun 2005, Pit Capitain wrote:

    > Ara.T.Howard schrieb:
    >> wow! it __can__ be done. now someone try to break it please! ;-)

    >
    > Ask and thou shalt receive:
    >
    >> (previous code)

    >
    > def a; "ouch"; end
    >
    >> set_var 'a', 42
    >> p a

    >
    > You get a name clash between methods and local variables. Otherwise, your
    > code should work fine, AFAIKT.


    hmm. i guess here

    def a; 'forty-two'; end

    set_var 'a', 42
    p a

    we get the method. and here

    def a; 'forty-two'; end

    a = 42
    p a

    we get the local_variable. so in either case you get a name clash - but the
    sense of it is reversed with set_var. i wonder if this is un-intuitive enough
    to render it useless?

    cheers.

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    Ara.T.Howard, Jun 2, 2005
    #18
  19. > ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/a.rb

    If this is to avoid 'cat', then you could also use

    ~ > ruby -e'puts *ARGF' sample/a.rb
     
    Sean O'Halpin, Jun 2, 2005
    #19
  20. Ara.T.Howard

    Guest

    On Fri, 3 Jun 2005, Sean O'Halpin wrote:

    >> ~ > ruby -e'puts(IO::read(ARGV.shift))' sample/a.rb

    >
    > If this is to avoid 'cat', then you could also use
    >
    > ~ > ruby -e'puts *ARGF' sample/a.rb


    i'll take it ;-)

    -a
    --
    ===============================================================================
    | email :: ara [dot] t [dot] howard [at] noaa [dot] gov
    | phone :: 303.497.6469
    | My religion is very simple. My religion is kindness.
    | --Tenzin Gyatso
    ===============================================================================
     
    , Jun 2, 2005
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mike Sampson [MSFT]

    [ANN]: NNTP Server slow downs.

    Mike Sampson [MSFT], Oct 7, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    421
    Mike Sampson [MSFT]
    Oct 7, 2003
  2. Mike Sampson [MSFT]

    [ANN]: NNTP Server slow downs.

    Mike Sampson [MSFT], Dec 6, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    508
    Mike Sampson [MSFT]
    Dec 6, 2003
  3. Richard Grimes [MVP]

    ANN: Free .NET Workshops

    Richard Grimes [MVP], Jul 4, 2005, in forum: ASP .Net
    Replies:
    0
    Views:
    510
    Richard Grimes [MVP]
    Jul 4, 2005
  4. Michael Livsey
    Replies:
    3
    Views:
    436
    Michael Livsey
    May 27, 2004
  5. Ara.T.Howard

    [ANN] parseargs-0.1.0

    Ara.T.Howard, Jun 13, 2005, in forum: Ruby
    Replies:
    0
    Views:
    98
    Ara.T.Howard
    Jun 13, 2005
Loading...

Share This Page