lib/volt/watch.rb
def on_deep_change_in(*roots, except: nil, &block)
      roots.each do |root|
        ensure_reactive(root)
        traverse(root, :node, except, true, block)
      end
    end
def on_deep_change_in(*roots, except: nil, &block)
      roots.each do |root|
        ensure_reactive(root)
        traverse(root, :node, except, true, block)
      end
    end
Does a deep traversal of all values reachable from
 the given root object(s).

 Such values include:
   * attributes and field values of Volt::Model's
   * size and elements of Volt::ArrayModel's
   * size and elements of Volt::ReactiveArray's
   * size and key-value pairs of Volt::ReactiveHash's
   * nested values of the above

 The root(s) may be a Volt::Model, Volt::ArrayModel,
 Volt::ReactiveArray or Volt::ReactiveHash.

 The given block may accept one, two or three arguments.

 The block will be called when any value reachable from
 (one of) the root(s) changes.
   1. the model (owner) of the value that changed
      i.e. the model, array or hash holding the value
   2. the locus of the value, either:
      * the attribute or field name for a model
      * the index in an array
      * the key in a hash
      * the symbol :size if array or hash size changes
   3. the new value
 The block may choose to accept 2 or 3 arguments.
 This mode is suitable when watching for deep changes
 to the contents of a model/array/hash and you DO need
 to identify what value that changed.

 In both modes, an optional argument specifying attributes
 you don't want to watch may be given with the :except
 keyword argument. The argument should be a symbol or
 integer or array of symbols or integers matching model
 attributes, array indexes or hash keys which you wish
 to ignore changes to. It may also include `:size` if you
 wish to ignore changes to the size of arrays or hashes.
 TODO: make :except more precise, perhaps with pairs of
 [parent, locus] to identify exceptions more accurately.
 Also allow for [Class, locus] to except any object of
 the given class.

 For example:

 ```
   class Contact < Volt::Model
     field :street
     field :city
     field :zip
     field :country
     field :phone
     field :email
   end

   class Customer < Volt::Model
     field :name
     field :contact
   end

   class Order < Volt::Model
     field :customer
     field :product
     field :date
     field :quantity
   end

   ...

   def deep_order_watch
     # one argument in given block has no detail of change
     on_deep_change_in orders do |store._orders|
       puts "something unknown changed in orders"
     end
   end

   def on_deep_change_in
     # three arguments in given block gives detail of change
     on_deep_change_in store._orders do |context, locus, value|
       case
         when context == store._orders
           if locus == :size
             puts "orders.size has changed to #{value}"
           else
             index = locus
             puts "orders[#{index}] has changed to #{value}"
           end
         when context.is_a? Order
           order, attr = context, locus
           puts "Order[#{order.id}].#{attr} has changed to #{value}"
         when context.is_a? Customer
           customer, attr = context, locus
           puts "customer #{customer.id} #{attr} has changed to #{value}"
       end
     end
   end
 ```