Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Parse Ruby source code in Clojure, and more

branch: master
README.md

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.

Something went wrong with that request. Please try again.