Skip to content

provide a customable map like function to explore any tree

Notifications You must be signed in to change notification settings

maxigit/ruby_walk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction

This gem provides the walk_objets function, ie a map like function to any arbitrary tree. This can be used either to generate a flat list of an object and its dependencies or to just to iterate recursively over them. Each object is only walked once, The tree is explored using a hash describing for each class, which methods to call. This can be either a symbol, a list of symbol or Proc to execute.

Examples

Lets consider a Rails like example

   Class User
     has_many :posts
   end

:

   Class Post
     :has_many :comments
   end

: :

   user.walk_objects(:user => [:posts], :posts =>[:comments])

will generate a list containing, the user, all its posts, and all of the associated comments

Filtering

to filter the element to be walked use a block. If a block return nil then element and its dependencies are skiped. If the result is [] the element is not returned in the result but its dependencies are walked. You can also return a Cut object to return an objet without walking it.

With the previous example, to get only the list of comments

   user.walk_objects(:user => :posts, :posts =>:comments) { |e| e.is_a?(Comment) ? e : []}

To not walk a particular user

   me = User.find('me')
   user.walk_objects(:user => :posts, :posts =>:comments) { |e| e == me ? :    RubyWalk::Cut.new(e) : e }

Walking over a hash

use :keys and or :values.

To get all the final value of a Hash

   > {:a=>1, :b=>2, :c=>{:a=>3, :d=>5}}.walk_objects(Hash => :values){ |e| e.is_a?(Hash) ? [] : e }
   [1, 2, 3, 5]

Walking over a list

by default a List walk over its elements and excludes itself.

   > [[1, 2], [3, 2], [[5, 6, [7, 8]]]].walk_objects(){ |x| x*10 }
   [10, 20, 30, 50, 60, 70, 80]              

Breaking mode cycles. Multistep walk.

You might need to have different dependencies for the same class depending of the depth or break a cycle in the dependencies. The easiest to do so it to chain walk (or do a multiplestep walk).

Imagine in the previous example , you want to walk through the users for each comments. Adding Comment => :users like this

   user.walk_objects(:user => :posts, :posts =>:comments, Comment => :users)

will cycle trough users and pull every posts from the users which had left a comment on our post. Instead chain 2 walks.

   user.walk_objects(:user => :posts, :posts =>:comments).walk_objects(Comment => :users)

Only the root user, will have the posts walked through.

You can also pass an array of hashes to the walk methods

   user.walk_objects([{:user => :posts, :posts =>:comments}, {Comment => :users}])

Inheritance

By default the methods described in the “model tree” for a subclass are merged with the superclass. To avoid that, use the special method :skip_super.

   class A
     def f
        ...
     end
   end
   class B < A
     def g
        ...
     end
   end

Walking with the parameter { :a => :f, :b=> :g } will pull f, and g for the class B. To pull only g , use { :a => :f, :b=> [:g, :skip_super] }.

Advanced

Walking over edges

by passing extra arguments to a block, you can get usefull edge information as:

  • parent
  • index : rank of the current object within parent
  • max_index : number total of sibbling

At the moment Array are not considered as a parent and set the parent of the Array if it exists.

   > %w{a b c d}.walk_objects { |x, parent, index| {x => index }}
   [{"a"=>0}, {"b"=>1}, {"c"=>2}, {"d"=>3}]  

About

provide a customable map like function to explore any tree

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages