Skip to content

mrb/graaaph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

graaaph

graaaph is a Clojure library designed to make it easy to consume, manipulate, and analyze JRuby's AST representation of Ruby code from Clojure. It ties together a bunch of interesting Clojure libraries in the hopes of creating a unified Clojure toolkit for exploring generated Ruby ASTs.

Ruby code is parsed and transformed by the Java jruby-parser library, manipulated by Clojure's zipper library, analyzed with core.logic, and visualized using @ztellman's Rhizome.

Usage

Get code as a map, with a lot of data:

(use 'graaaph.core)

(parse-ruby-code "def a;'ok';end")

;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 0, :end-offset 14}, :type "ROOTNODE", :value nil, :name nil}
;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 0, :end-offset 14}, :type "NEWLINENODE", :value nil, :name nil}
;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 0, :end-offset 14}, :type "DEFNNODE", :value nil, :name "a"}
;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 4, :end-offset 5}, :type "ARGUMENTNODE", :value nil, :name "a"}
;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 6, :end-offset 6}, :type "ARGSNODE", :value nil, :name nil}
;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 6, :end-offset 11}, :type "NEWLINENODE", :value nil, :name nil}
;; {:position {:file "", :start-line 0, :end-line 0, :start-offset 6, :end-offset 10}, :type "STRNODE", :value nil, :name nil}

Or as a zipper, but still tasting like Java:

(use 'graaaph.core)

(-> (ruby-code-zipper "1")
    z/next
    z/next
    z/node
    .getValue) ;; From the jruby-parser API
;; 1

Or use one of a (slowly) growing number of core.logic relations such as nodetypeo and dupeo:

(def ruby-code "class Dude
                  def awesome
                    'first awesome'
                  end
                  #
                  def cool
                    'not awesome'
                  end
                  #
                  def awesome
                    'second awesome'
                  end
                  #
                  def bro
                  end
                  #
                  def bro
                  end
                end")

(defn get-duplicate-method-names [ruby-code]
  (let [nodes   (parse-ruby-code ruby-code)
        results (l/run* [q]
                  (l/fresh [a b c d]
                    (l/== a nodes)
                    (nodetypeo a "DEFNNODE" c)
                    (dupeo c d)
                    (l/== q d)))]
        results))

(get-duplicate-method-names ruby-code)
;;=> (({:type "DEFNNODE", :value nil, :name "awesome"} {:type "DEFNNODE", :value nil, :name "bro"}))

Examine your ast by generating an image of the tree

(view-ruby-ast ruby-code)

;; or save it as a file
(save-ruby-ast-image ruby-code "tree.png")

Transform source code with a zipper and then transform back to source code

(ruby-code-zipper ruby-code)
;; [#<RootNode (RootNode, (NewlineNode, (ClassNode, (Colon2ImplicitNode:Dude), (BlockNode, (NewlineNode, (DefnNode:awesome, (ArgumentNode:awesome), (ArgsNode), (NewlineNode, (StrNode)))), (NewlineNode, (DefnNode:cool, (ArgumentNode:cool), (ArgsNode), (NewlineNode, (StrNode)))), (NewlineNode, (DefnNode:awesome, (ArgumentNode:awesome), (ArgsNode), (NewlineNode, (StrNode)))), (NewlineNode, (DefnNode:bro, (ArgumentNode:bro), (ArgsNode))), (NewlineNode, (DefnNode:bro, (ArgumentNode:bro), (ArgsNode)))))))> nil]

(zipper-to-source (ruby-code-zipper ruby-code))
#<StringWriter class Dude
  def awesome
    "first awesome"
  end
  def cool
    "not awesome"
  end
  def awesome
    "second awesome"
  end
  def bro
  end
  def bro
  end
end>

Tests

lein test

Plans

  • Associate original jruby-parser node information as metadata to node map object, for altering and rehydrating source as ast

Credits

  • @swannodette for the amazing guidance and work on nodeattro, mapo, filtero, rembero, etc.

License

Copyright © 2013 Michael R. Bernstein and contributors

Distributed under the Eclipse Public License, the same as Clojure.

About

Parse Ruby source code in Clojure, and more

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published