tickly 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|