= tickly A highly simplistic TCL parser and evaluator (primarily designed for parsing Nuke scripts). It structures the passed Nuke scripts into a TCL AST and return it. You can use some cheap tricks to discard the nodes you are not interested in. == Plain parsing Create a Parser object and pass TCL expressions/scripts to it. You can pass IO obejcts or strings. Note that parse() will always return an Array of expressions, even if you only fed it one expression line. For example: p = Tickly::Parser.new # One expression, even if it's invalid (2 is not a valid TCL bareword - doesn't matter) p.parse '2' #=> [["2"]] # TCL command p.parse "tail $list" #=> [["tail", "$list"]] # Multiple expressions p.parse "2\n2" #=> [["2"], ["2"]] # Expressions in curly braces p.parse '{2 2}' #=> [[:c, "2", "2"]] # Expressions in square brackets p.parse '{exec cmd [fileName]}' #=> [[:c, "exec", "cmd", [:b, "fileName"]]] The AST is represented by simple arrays. An array is a TCL expression. An array with the :c symbol at the beginning element is an expression in curly braces. An array with the :b symbol at the beginning represents an expression with string interpolations in it. If you are curious, :c stands for "curlies" and :b for "brackets". All the other array elements are guaranteed to be strings. Multiple expressions separated by ; or a newline will be accumulated as multiple arrays. Lots and lots of TCL features are not supported - remember that most Nuke scripts are machine-generated and they do not use most of the esoteric language features. == Evaulating nodes in Nuke scripts What you are likely to use Tickly for is parsing Nuke scripts. They got multiple node definitions, which are actially arguments for a node constructor written out in TCL. Consider this ubiquitous fragment for a hypothetic SomeNode in your script: SomeNode { someknob 15 anotherknob 3 animation {curve x1 12 45 67} x_pos 123 y_pos -10 } and so on. You can use a NodeProcessor to capture these node constructors right as they are being parsed. All the nodes you are not interested in will be discarded, which matters in terms of memory use. To do it you need to create Ruby classes matching the node classes by name. For example, for that SomeNode of ours: class SomeNode attr_reader :knobs def initialize(string_keyed_knobs_hash) @knobs = string_keyed_knobs_hash end end # Instantiate a new processor e = Tickly::NodeProcessor.new # Add the class e.add_node_handler_class Blur file = File.open("/mnt/raid/nuke/scripts/HugeShot_123.nk") e.parse(file) do | every_some_node | # Everytime a SomeNode is found in the script it will be instantiated, # and the knobs of the node will be passed to the constructor that you define x_position = every_some_node.knobs["x_pos"] ... end If you are curious, this is how Tracksperanto parses various nodes containing tracking data: parser = Tickly::NodeProcessor.new parser.add_node_handler_class(Tracker3) parser.add_node_handler_class(Reconcile3D) parser.add_node_handler_class(PlanarTracker1_0) parser.add_node_handler_class(Tracker4) == Animation curves You can parse Nuke's animation curves using Tickly::Curve. This will give you a way to iterate over every defined keyframe. This currently does not happen automatically for things passing through the parser. == Contributing to tickly * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet. * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it. * Fork the project. * Start a feature/bugfix branch. * Commit and push until you are happy with your contribution. * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally. * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it. == Copyright Copyright (c) 2013 Julik Tarkhanov. See LICENSE.txt for further details.