tickly 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/README.rdoc +36 -15
- data/lib/tickly.rb +1 -1
- data/lib/tickly/parser.rb +8 -5
- data/tickly.gemspec +5 -5
- metadata +5 -5
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
A highly simplistic TCL parser and evaluator (primarily designed for parsing Nuke scripts). It structures
|
4
4
|
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.
|
5
5
|
|
6
|
-
==
|
6
|
+
== Plain parsing
|
7
7
|
|
8
8
|
Create a Parser object and pass TCL expressions/scripts to it. You can pass IO obejcts or strings. Note that parse()
|
9
9
|
will always return an Array of expressions, even if you only fed it one expression line. For example:
|
10
10
|
|
11
11
|
p = Tickly::Parser.new
|
12
12
|
|
13
|
-
# One expression, even if it's invalid (2 is not a valid TCL bareword
|
13
|
+
# One expression, even if it's invalid (2 is not a valid TCL bareword - doesn't matter)
|
14
14
|
p.parse '2' #=> [["2"]]
|
15
15
|
|
16
16
|
# TCL command
|
@@ -35,40 +35,61 @@ Multiple expressions separated by ; or a newline will be accumulated as multiple
|
|
35
35
|
Lots and lots of TCL features are not supported - remember that most Nuke scripts are machine-generated and they do not
|
36
36
|
use most of the esoteric language features.
|
37
37
|
|
38
|
-
== Evaulating
|
38
|
+
== Evaulating nodes in Nuke scripts
|
39
39
|
|
40
|
-
|
40
|
+
What you are likely to use Tickly for is parsing Nuke scripts. They got multiple node definitions, which
|
41
|
+
are actially arguments for a node constructor written out in TCL. Consider this ubiquitous fragment for a
|
42
|
+
hypothetic SomeNode in your script:
|
41
43
|
|
42
44
|
SomeNode {
|
43
45
|
someknob 15
|
44
46
|
anotherknob 3
|
45
|
-
|
47
|
+
animation {curve x1 12 45 67}
|
48
|
+
x_pos 123
|
49
|
+
y_pos -10
|
46
50
|
}
|
47
51
|
|
48
|
-
and so on. You can use a
|
49
|
-
the evaulation you need to create classes matching the node classes by name. For example, a Blur class:
|
52
|
+
and so on. You can use a NodeProcessor to capture these node constructors right as they are being parsed.
|
50
53
|
|
51
|
-
|
54
|
+
All the nodes you are not interested in will be discarded, which matters in terms of memory use.
|
55
|
+
|
56
|
+
To do it you need to create Ruby classes matching the node classes by name. For example, for that SomeNode
|
57
|
+
of ours:
|
58
|
+
|
59
|
+
class SomeNode
|
60
|
+
attr_reader :knobs
|
52
61
|
def initialize(string_keyed_knobs_hash)
|
62
|
+
@knobs = string_keyed_knobs_hash
|
53
63
|
end
|
54
64
|
end
|
55
65
|
|
56
|
-
|
66
|
+
# Instantiate a new processor
|
67
|
+
e = Tickly::NodeProcessor.new
|
68
|
+
|
69
|
+
# Add the class
|
57
70
|
e.add_node_handler_class Blur
|
58
71
|
|
59
|
-
|
72
|
+
file = File.open("/mnt/raid/nuke/scripts/HugeShot_123.nk")
|
60
73
|
|
61
|
-
|
62
|
-
# Everytime a
|
74
|
+
e.parse(file) do | every_some_node |
|
75
|
+
# Everytime a SomeNode is found in the script it will be instantiated,
|
63
76
|
# and the knobs of the node will be passed to the constructor that you define
|
64
|
-
|
65
|
-
|
66
|
-
end
|
77
|
+
x_position = every_some_node.knobs["x_pos"]
|
78
|
+
...
|
67
79
|
end
|
68
80
|
|
81
|
+
If you are curious, this is how Tracksperanto parses various nodes containing tracking data:
|
82
|
+
|
83
|
+
parser = Tickly::NodeProcessor.new
|
84
|
+
parser.add_node_handler_class(Tracker3)
|
85
|
+
parser.add_node_handler_class(Reconcile3D)
|
86
|
+
parser.add_node_handler_class(PlanarTracker1_0)
|
87
|
+
parser.add_node_handler_class(Tracker4)
|
88
|
+
|
69
89
|
== Animation curves
|
70
90
|
|
71
91
|
You can parse Nuke's animation curves using Tickly::Curve. This will give you a way to iterate over every defined keyframe.
|
92
|
+
This currently does not happen automatically for things passing through the parser.
|
72
93
|
|
73
94
|
== Contributing to tickly
|
74
95
|
|
data/lib/tickly.rb
CHANGED
data/lib/tickly/parser.rb
CHANGED
@@ -19,7 +19,7 @@ module Tickly
|
|
19
19
|
def parse(io_or_str)
|
20
20
|
bare_io = io_or_str.respond_to?(:read) ? io_or_str : StringIO.new(io_or_str)
|
21
21
|
# Wrap the IO in a Bychar buffer to read faster
|
22
|
-
reader = Bychar
|
22
|
+
reader = Bychar.wrap(bare_io)
|
23
23
|
# Use multiple_expressions = true so that the top-level parsed script is always an array
|
24
24
|
# of expressions
|
25
25
|
sub_parse(reader, stop_char = nil, stack_depth = 0, multiple_expressions = true)
|
@@ -27,7 +27,10 @@ module Tickly
|
|
27
27
|
|
28
28
|
# Override this to remove any unneeded subexpressions.
|
29
29
|
# Return the modified expression. If you return nil, the result
|
30
|
-
# will not be added to the expression list
|
30
|
+
# will not be added to the expression list. You can also use this
|
31
|
+
# method for bottom-up expression evaluation, returning the result
|
32
|
+
# of the expression being evaluated. This method will be first called
|
33
|
+
# for the innermost expressions and then proceed up the call stack.
|
31
34
|
def compact_subexpr(expr, at_depth)
|
32
35
|
expr
|
33
36
|
end
|
@@ -62,7 +65,7 @@ module Tickly
|
|
62
65
|
last_char_was_linebreak = false
|
63
66
|
|
64
67
|
no_eof do
|
65
|
-
char = io.
|
68
|
+
char = io.read_one_char!
|
66
69
|
|
67
70
|
if char == stop_char # Bail out of a subexpr
|
68
71
|
# Handle any remaining subexpressions
|
@@ -114,14 +117,14 @@ module Tickly
|
|
114
117
|
def no_eof(&blk)
|
115
118
|
begin
|
116
119
|
loop(&blk)
|
117
|
-
rescue Bychar::
|
120
|
+
rescue Bychar::EOF
|
118
121
|
end
|
119
122
|
end
|
120
123
|
|
121
124
|
def parse_str(io, stop_char)
|
122
125
|
buf = ''
|
123
126
|
no_eof do
|
124
|
-
c = io.
|
127
|
+
c = io.read_one_char!
|
125
128
|
if c == stop_char && buf[LAST_CHAR] != ESC
|
126
129
|
return buf
|
127
130
|
elsif buf[LAST_CHAR] == ESC # Eat out the escape char
|
data/tickly.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "tickly"
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Julik Tarkhanov"]
|
12
|
-
s.date = "2013-03-
|
12
|
+
s.date = "2013-03-23"
|
13
13
|
s.description = "Parses the subset of the TCL grammar needed for Nuke scripts"
|
14
14
|
s.email = "me@julik.nl"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -55,14 +55,14 @@ Gem::Specification.new do |s|
|
|
55
55
|
s.specification_version = 3
|
56
56
|
|
57
57
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
|
-
s.add_runtime_dependency(%q<bychar>, ["~>
|
58
|
+
s.add_runtime_dependency(%q<bychar>, ["~> 2"])
|
59
59
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
60
60
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
61
61
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
62
62
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
63
63
|
s.add_development_dependency(%q<ruby-prof>, [">= 0"])
|
64
64
|
else
|
65
|
-
s.add_dependency(%q<bychar>, ["~>
|
65
|
+
s.add_dependency(%q<bychar>, ["~> 2"])
|
66
66
|
s.add_dependency(%q<rake>, [">= 0"])
|
67
67
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
68
68
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
@@ -70,7 +70,7 @@ Gem::Specification.new do |s|
|
|
70
70
|
s.add_dependency(%q<ruby-prof>, [">= 0"])
|
71
71
|
end
|
72
72
|
else
|
73
|
-
s.add_dependency(%q<bychar>, ["~>
|
73
|
+
s.add_dependency(%q<bychar>, ["~> 2"])
|
74
74
|
s.add_dependency(%q<rake>, [">= 0"])
|
75
75
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
76
76
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tickly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bychar
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
21
|
+
version: '2'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '2'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: rake
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,7 +157,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
157
|
version: '0'
|
158
158
|
segments:
|
159
159
|
- 0
|
160
|
-
hash:
|
160
|
+
hash: -720429447261605785
|
161
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
162
|
none: false
|
163
163
|
requirements:
|