Defining a custom to_yaml method to inline hashes

check out the following:

   jib:~ > cat a.rb
   require 'yaml'

   # yaml can load inline hashes
   inline_hash = YAML::load "--- { jid: 121, metric: started, time: 2005-05-10 08:18:22.523016 }"

   puts '=' * 8
   y inline_hash
   puts

   # attempt to bludgeon to object into emitting in an inline fashion
   class << inline_hash
     def to_yaml(*a, &b)
       '{ ' << map{|kv| kv.join(': ')}.join(', ') << ' }'
     end
   end

   # looks good at first
   puts '=' * 8
   y inline_hash
   puts

   # but doesn't really work after all when part of another object
   puts '=' * 8
   y({'running' => inline_hash})
   puts

   jib:~ > ruby a.rb

···

========
   ---
   time: 2005-05-10 08:18:22.523016
   jid: 121
   metric: started

   ========
   { time: 2005-05-10 08:18:22.523016, jid: 121, metric: started }

   ========
   ---
   running:

notice the second block is alright but the third is not. i know i need to do
something like

   def to_yaml(*a, &b)
     YAML::quick_emit(*a, &b) do |out|
       # now what?
     end
   end

but can't seem to find anything in the docs or samples.

cheers.

-a
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

this seems o.k. - can anyone verify this is an o.k. approach?

   jib:~ > cat a.rb
   require 'yaml'
   class Hash
     def yaml_inline= bool
       unless defined? @__yaml_inline_meth
         @__yaml_inline_meth =
           lambda {|opts|
             YAML::quick_emit(id, opts) {|emitter|
               emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
             }
           }
         class << self
           def to_yaml opts = {}
             @__yaml_inline ? @__yaml_inline_meth[ opts ] : super
           end
         end
       end
       @__yaml_inline = bool
     end
   end

   hash = { 'jid' => 121, 'metric' => 'started', 'time' => '2005-05-10 08:18:22.523016' }

   y 'hash' => hash
   puts

   hash.yaml_inline = true
   y 'hash' => hash
   puts

   hash.yaml_inline = false
   y 'hash' => hash
   puts

   jib:~ > ruby a.rb

···

On Wed, 11 May 2005, Ara.T.Howard wrote:

check out the following:

jib:~ > cat a.rb
require 'yaml'

# yaml can load inline hashes
inline_hash = YAML::load "--- { jid: 121, metric: started, time: 2005-05-10 08:18:22.523016 }"

puts '=' * 8
y inline_hash
puts

# attempt to bludgeon to object into emitting in an inline fashion
class << inline_hash
   def to_yaml(*a, &b)
     '{ ' << map{|kv| kv.join(': ')}.join(', ') << ' }'
   end
end

# looks good at first
puts '=' * 8
y inline_hash
puts

# but doesn't really work after all when part of another object
puts '=' * 8
y({'running' => inline_hash})
puts

jib:~ > ruby a.rb

---
time: 2005-05-10 08:18:22.523016
jid: 121
metric: started

========
{ time: 2005-05-10 08:18:22.523016, jid: 121, metric: started }

========
---
running:

notice the second block is alright but the third is not. i know i need to do
something like

def to_yaml(*a, &b)
   YAML::quick_emit(*a, &b) do |out|
     # now what?
   end
end

but can't seem to find anything in the docs or samples.

   ---
   hash:
     time: 2005-05-10 08:18:22.523016
     jid: 121
     metric: started

   ---
   hash: { time: 2005-05-10 08:18:22.523016, jid: 121, metric: started }

   ---
   hash:
     time: 2005-05-10 08:18:22.523016
     jid: 121
     metric: started

of course this only works with kvs as strings....

-a
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

> # attempt to bludgeon to object into emitting in an inline fashion
> class << inline_hash
> def to_yaml(*a, &b)
> '{ ' << map{|kv| kv.join(': ')}.join(', ') << ' }'
> end
> end

Hacking Syck 0.45 or less will be very involved. Consider that inline
collections must also contain inline hashes and inline arrays. And, as
your sample code demonstrated, some strings which get formatted in the
"folded" or "literal" block styles won't jive with inlines.

Syck 0.53 and up is a different story. You can easily emit inlines by
defining a `to_yaml_style' method.

  >> require 'yaml'
  >> a = {'time' => Time.now, 'jid' => 121, 'metric' => 'started'}
  >> def a.to_yaml_style; :inline; end
  >> y a
  => ---
     { time: 2005-05-10 08:18:22.523016, jid: 121, metric: started }

The new Syck emitter will ensure that everything inside the inline is
properly output. I still need to improve the pretty printer, but it
works.

this seems o.k. - can anyone verify this is an o.k. approach?

  jib:~ > cat a.rb
  require 'yaml'
  class Hash
    def yaml_inline= bool
      unless defined? @__yaml_inline_meth
        @__yaml_inline_meth =
          lambda {|opts|
            YAML::quick_emit(id, opts) {|emitter|
              emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
            }
          }
        class << self
          def to_yaml opts = {}
            @__yaml_inline ? @__yaml_inline_meth[ opts ] : super
          end
        end
      end
      @__yaml_inline = bool
    end
  end

This will work for very simple hashes, but will break down upon
encountering multiline strings or any kind of object, array, hash, etc.

While Syck 0.5x isn't ready for primetime, it's getting very close. I
could use help debugging and the time you spend debugging could yield a
stable Syck in the next two months.

_why

···

Ara.T.Howard@noaa.gov (Ara.T.Howard@noaa.gov) wrote:

On Wed, 11 May 2005, Ara.T.Howard wrote: