Skip to content

Commit ac41c9d

Browse files
committed
Add blog post source (not 100% up to date with text on blog though).
1 parent 82ddbbf commit ac41c9d

File tree

9 files changed

+1138
-0
lines changed

9 files changed

+1138
-0
lines changed

about-scope.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
Scope Stuffs
2+
===
3+
4+
Node Scope
5+
---
6+
* People want access to node scope
7+
* What is node scope vs. top scope
8+
* What happens with shadowing when loaded code sets things in top scope
9+
10+
Access to Node Scope
11+
---
12+
For node scope to become addressable it needs to be in a namespace, and this namespace
13+
is always the same (since users will reference things in "current node scope" (not for some
14+
other node).
15+
16+
Alternatively, this can be available via a type. Node[name] could be a reference to a particular
17+
node's scope. ThisNode could be a reference to the current evaluating node. The later could accept reference to its parameters - i.e. `ThisNode[msg]` would get $msg in nodescope.
18+
19+
We can also create a named scope, even setting of a variable in node scope (say $x) becomes
20+
a setting in `$nodescope::x`, and this thus both shadowing and globally accessible.
21+
22+
Node Scope vs Top Scope
23+
---
24+
25+
If autoloaded code has code in top scope - what should happen when a variable is set?
26+
27+
* It is set in top scope and potentially (already) shadowed in node scope
28+
* It is set in node scope, and potentially clashes (mutation attempt error)
29+
* node scope does not exist - a new top scope being a merge is set as the global scope (and
30+
all top scope settings after that are clashes
31+
32+
We may also forbid all top scope assignments in auto loaded code.
33+
34+
Match Scope
35+
---
36+
A match scope is constructed based on a regular expression match. There is however a problem
37+
in that a sequence of statements should retain the last match scope. For this reason,
38+
scope must handle match result in a special way.
39+
40+
When a match is made, the match data should simply be set in scope. When entering an expression
41+
that preserves the current match data, it should create a new MatchScope (transparent to everything
42+
except match data).
43+
44+
Performance Improvements
45+
---
46+
Numeric variable detection is a performance problem, every lookup in every scope has to check
47+
if the variable name is numeric. We can solve this by creating a special instruction
48+
for numeric variables and have a special lookup of these via dedicated lookup / exists. This
49+
then completely removes the need to look at the variable name string.
50+
51+
We can probably also speed up by differentiating between SimpleName, and QualifiedName. Thi
52+
because we only have to check for '::' when it is constructed. We may also keep the value
53+
around in both concatenated and split form to avoid having to split and combine it multiple
54+
times.
55+
56+
Discussion
57+
===
58+
59+
Node Scope is a transaction specific context around the logic being evaluated. If it shadows
60+
there should really be no way to break out from that shadowing and read the non shadowed variables.
61+
(i.e. no breaking of the encapsulation).
62+
63+
This means that all top scope assignments (if allowed) in autoloaded code should be set in
64+
the node scope - i.e. there is no difference between it and the top scope and they could just as well be merged right away.

blog-posts/heredoc.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
Heredoc is here! Starting with Puppet 3.5.0 with --parser future turned on you can now
2+
use Puppet Heredoc; basically a way to write strings of text without having to escape/quote special
3+
characters. The primary motivation for adding heredoc support to the Puppet Programming Language
4+
is to help avoiding the problem known as "backslash hell", where every backslash character in a
5+
string may require, two, four or more backslashes to pass an actual backslash through multiple layers
6+
of string special character interpretation.
7+
8+
Before talking about the features of Puppet Heredoc, lets look at an example:
9+
10+
$a = @(END)
11+
This is the text that gets assigned to $a.
12+
And this too.
13+
END
14+
15+
As you probably already figured out, the `@()` is the heredoc start tag, where you get to
16+
define what the end tag is; a text string that marks where the verbatim sequence of text on the lines
17+
following the start tag ends. In the example above, the end tags is `END`. (Obviously you have
18+
to select an end tag that does not appear as a separate line inside the actual text).
19+
20+
This blog post is a brief introduction of the Puppet Heredoc features, the full specification
21+
is found in the [Puppet Heredoc ARM-4 text][1].
22+
23+
[1]:https://github.com/puppetlabs/armatures/blob/master/arm-4.heredoc/heredoc.md
24+
25+
### Trying out the examples
26+
27+
If you want to try out the examples, you need Puppet 3.5.0 and then turn on --parser future.
28+
29+
### Controlling the Left Margin
30+
31+
A problem with Heredoc is how to deal with text that appears in indented text, but you
32+
do not want the indentation in the resulting string.
33+
34+
if $something {
35+
$a = @(END)
36+
Text here is indented 2 spaces.
37+
END
38+
}
39+
40+
Puppet Heredoc solves this by allowing you to define where the left margin is by using
41+
a pipe `|` character on the end-tag line at the position where the first character on each line
42+
should be. To fix the example above, we then write:
43+
44+
if $something {
45+
$a = @(END)
46+
Text here is indented 2 spaces.
47+
| END
48+
}
49+
50+
### Controlling trailing new-line
51+
52+
Another problem with heredoc text is how to deal with the line ending of the last line
53+
of text (and any trailing whitespace on that line). With Puppet Heredoc you can easily strip
54+
out trailing space and the newline by using a `-` before the end tag. (You can combine the - with | by placing the - after the pipe).
55+
56+
Here is the same example again, now without trailing new-line in the result:
57+
58+
if $something {
59+
$a = @(END)
60+
Text here is indented 2 spaces.
61+
|- END
62+
}
63+
64+
### Interpolating variables
65+
66+
The default mode of Puppet Heredoc is to not interpolate variables (e.g. having `$a` in the
67+
heredoc text does not expand to the value of the variable `$a`). If you need this, it is possible
68+
to turn on interpolation by double quoting the specification of the end tag.
69+
70+
$a = world
71+
notice @("END")
72+
The $a is an awesome place
73+
|- END
74+
75+
Will output "The world is an awesome place".
76+
77+
Naturally, since there also needs to be a way to enter a `$`, escaping is turned on for `$` and for `\`. Thus when using interpolation, a `\` must be entered as `\\`, and a `$` as `\$`.
78+
79+
You can use both styles of interpolation; either just `$a`, or `${a}`. The same rules for interpolation of expression as for double quoted strings apply.
80+
81+
### Controlling Special Character Escapes
82+
83+
By default, all character escapes are turned off (when using interpolation escapes for \ and $ are turned on). Puppet Heredoc also allows you to control escapes in more detail. The possible escapes are t, s, r, n, u, L, and $, and you can control these individually by specifying them in the heredoc start tag like this:
84+
85+
$a = @(END/tL)
86+
This text has a tab\t and joins this line \L
87+
with this line.
88+
|-END
89+
90+
Most of the escapes should be familiar, except the `L` escape which makes it possible to escape
91+
the end of line thus effectively joining a line with the next. The charters may appear in any order
92+
in the spec. Using one (or more) escapes also always turn on escaping of `\`.
93+
94+
### Specifying the Syntax
95+
96+
The Puppet Heredoc start tag allows specification of the syntax of the contained text. This is done by following the end tag name with ':', and the syntax/language specification as a mime specification string following the ':'. Here is an example:
97+
98+
$a = @(END:json)
99+
["a"]
100+
- END
101+
102+
The syntax/language tag serves dual purpose; it is an indicator to tools (such as Geppetto) how the tool should perform things like syntax highlighting or syntax checking, and it enables the Puppet Parser to perform syntax checking if there is a plugin that checks the given syntax.
103+
104+
In Puppet 3.5.0, there is a syntax checker for Json, and consequently, if you were to enter the
105+
following example, you will see it report the Json syntax error.
106+
107+
$a = @(END:json)
108+
['a']
109+
- END
110+
111+
You will get the following error:
112+
113+
Error: Invalid produced text having syntax: 'json'. JSON syntax checker: Cannot parse invalid JSON string. "unexpected token in array at ''a']'!"
114+
115+
New syntax checkers can be written in Ruby, and distributed as a Puppet Module. (This will be the topic of a future blog post).
116+
117+
### Summary
118+
119+
This blog post is an introduction to Puppet Heredoc. There are some additional features that are documented in the full ARM text, such as how to use multiple heredocs on the same line, the precise
120+
semantics of special character escapes and margin control, the details about what is permissible as
121+
an end-tag etc.
122+
123+
What better then to end with some poetry...
124+
125+
notice @(Verse 8 of The Raven)
126+
Then this ebony bird beguiling my sad fancy into smiling,
127+
By the grave and stern decorum of the countenance it wore,
128+
`Though thy crest be shorn and shaven, thou,' I said, `art sure no craven.
129+
Ghastly grim and ancient raven wandering from the nightly shore -
130+
Tell me what thy lordly name is on the Night's Plutonian shore!'
131+
Quoth the raven, `Nevermore.'
132+
| Verse 8 of The Raven
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
Puppet is a model driven system - a desired system state is modeled by describing the
2+
desired state of a set of resources, these are compiled into a catalog, and the catalog is
3+
applied to a system to make it have the desired modeled state.
4+
5+
What is new in the "future parser/evaluator" features in Puppet is that we started using modeling technology to implement how puppet itself works.
6+
7+
In this post, I am going to talk a bit about modeling in general, the Ecore modeling technology
8+
and the RGen Ruby implementation of Ecore.
9+
10+
### What is a "model" really?
11+
12+
If at first when you hear the word *model*, you think about Tyra Banks or Marcus Schenkenberg and then laugh a little because that is obviously not the kind of models we are talking about here, you are actually both right and wrong at the same time.
13+
14+
A model is an abstraction. We use abstractions all the time; when we talk about something like a "Car" we are talking about an unspecific instance of something like "a powered means of transportation, probably a 4 door sedan". Fashion models such as Tyra or Marcus are also abstractions of "people wearing clothes" albeit very good looking ones - in a way like if we design a Car icon to depict a Lamborghini, but now I am beginning to get off topic and into a completely different debate.
15+
16+
We can express a model concretely:
17+
18+
A Car has an engine, 2 to 5 doors, a steering wheel, breaks, and 4 wheels.
19+
. . .
20+
21+
We can also express such a model in a programming language:
22+
23+
class Car
24+
attr_accessor :engine
25+
attr_accessor :doors
26+
attr_accessor :steering_wheel
27+
attr_accessor :breaks
28+
attr_accessor :wheels
29+
30+
. . .
31+
end
32+
33+
As you can see in the above attempt to model a Car we lack the semantics in Ruby to declare
34+
more details about the Car's attributes - there is no way to declaratively state
35+
how many doors there could be, the number of wheels etc. There is also no way to declare
36+
that the engine attribute must be of engine type, etc. All such details must be implemented
37+
as logic in the setter and getter methods that manipulate a Car instance. While this is fine
38+
from a runtime perspective (it protects us from mistakes when using the class), we can not
39+
(at least not easily) introspect the class and deduce the number of allowed doors, or the allowed type of the various attributes.
40+
41+
While Ruby is a very fluid implementation language, in itself it is not very good at
42+
expressing a model.
43+
44+
### Modeling Language
45+
46+
A modeling language (in contrast to an implementation language such as Ruby) lets us
47+
describe far more details about the abstraction without having to express them in imperative
48+
code. One such family of "languages" are those that are used to describe data formats - they
49+
are referred to a schemas - and you are probably familiar with XmlSchema, JsonSchema, Yamlschema etc
50+
that allows a declaration to be made about what is allowed in data that conforms to the schema.
51+
52+
A schema is a form of modeling language. What is interesting about them is that it now possible
53+
to transform between them! Given an XmlSchema, it is possible to transform it into a corresponding
54+
Yaml or JsonSchema, and likewise transform data conformant with one such schema into data comformant
55+
with the transformed schema. (The problems doing this in practice has to do with the difference in semantic power between the different technologies - we may be able to express rules/constraints
56+
in one such schema technology that does not exist the others).
57+
58+
### Schemas and Meta Models
59+
60+
When we look at a schema - we are actually looking at a meta model; a model that describes a model.
61+
That is if we describe a car in Json we have a car model:
62+
63+
{ "engine": "combustion",
64+
"steering-wheel": "sport-leather",
65+
"wheels": ...
66+
}
67+
68+
And if we describe a schema for it:
69+
70+
{ "title": "Car Schema",
71+
"type"; "object",
72+
"properties": {
73+
"engine": { "type": "string"},
74+
"steering-wheel": { "type": "string" },
75+
. . .
76+
}
77+
"required": ["engine", "steering-wheel", ...]
78+
}
79+
80+
We have a Car meta-model.
81+
82+
In everyday speak, we typically refer to the schema as "schema" or "model" and simply ignore
83+
its "meta status". But since we are on the topic of meta models - what we can do now is to
84+
also express the meta model as a model - i.e. what is the schema for a jsonschema?
85+
Here is an excerpt from the [Json "Core/Validation Meta-Schema"][1]
86+
87+
{
88+
"id": "http://json-schema.org/draft-04/schema#",
89+
"$schema": "http://json-schema.org/draft-04/schema#",
90+
. . .
91+
"title": {
92+
"type": "string"
93+
},
94+
. . .
95+
"required": { "$ref": "#/definitions/stringArray" },
96+
. . .
97+
}
98+
99+
If you are interested in what it looks like, do download it. Be warned that you will quickly become
100+
somewhat disoriented since it is a schema describing a schema that describes what Json data
101+
should look like...
102+
103+
[1]:http://json-schema.org/documentation.html
104+
105+
A meta schema such as that for jsonschema is very useful as it can be used to validate schemas
106+
that describe data.
107+
108+
Schemas such as these are good for describing data, but they becomes somewhat difficult to use
109+
in practice for the construction of software. There are other modeling languages that are more specifically targeting software system constructs. There are both graphical and textual languages
110+
as well as those that have both types of representations.
111+
112+
What we are specifically interested in is an [Object modeling language][2]
113+
114+
[2]:http://en.wikipedia.org/wiki/Object_modeling_language
115+
116+
### Levels of reality / meta-ness
117+
118+
| level | Description |
119+
| --- | --- |
120+
| M0 | Real Object - e.g. the movie Casablance on a DVD |
121+
| M1 | User Model / Instance Level - e.g. a computer abstraction of the DVD - `aVideo = Video.new('Casablanca')` |
122+
| M2 | Meta Model - e.g. defines what `Video` is, its attributes and operations |
123+
| M3 | Meta meta model - e.g. defines how the definition of what a `Video` is, is expressed |
124+
125+
126+
### Object Modeling Language
127+
128+
An Object Modeling Language is a language that directly supports the kinds of elements we are interested in when constructing software. E.g. classes, methods, the properties of objects, etc. You probably heard of one such technology called [Unified Modeling Language][3] - this is a broad modeling technology and is associated with object oriented software development methodologies such as Booch, OMT, Objectory, IBM's RUP, and Dynamic Systems Development Method. This was the big thing in the 90's, but UML has since then more or less slid into darkness as "the way to write better
129+
software". An interesting debate from 2009, can be found [here][4].
130+
131+
[3]:http://en.wikipedia.org/wiki/Unified_Modeling_Language
132+
[4]:http://codebetter.com/jeremymiller/2009/09/12/how-relevant-is-uml-modeling-today/
133+
134+
There is however a very useful part of the UML technology that is often overlooked - the so
135+
called Meta Object Facility (MOF) that sits at the very core of UML and it contains the meta model
136+
that UML itself is defined in. MOF plays the same role for models as what Extended Backus Naur Form (EBNF) plays for programming languages - it defines the grammar. Thus MOF can be said to be a DSL used to define meta models. The technology used in MOF is called Ecore - it is the reference implementation of MOF.
137+
138+
### Ecore
139+
140+
Ecore is part of [Eclipse EMF][5], and is heavily used within Eclipse for a wide variety of
141+
IDE applications and application development domains. In the Puppet Domain Ecore technology is
142+
used in the [Puppetlabs Geppetto IDE][7] tool in combination with additional frameworks for language development [Xtext][6]
143+
144+
[5]:http://en.wikipedia.org/wiki/Eclipse_Modeling_Framework
145+
[6]:http://en.wikipedia.org/wiki/Xtext
146+
[7]:http://puppetlabs.github.io/geppetto/
147+
[8]:https://github.com/mthiede/rgen
148+
[9]:https://code.google.com/p/emf4cpp/
149+
150+
Eclipse EMF is a Java centric implementation of Ecore. There are also implementations for
151+
Ruby ([RGen][8], and C++ [EMF4CPP][9]).
152+
153+
Thus, there are many different ways to express an Ecore model. The UML MOF has defined one
154+
serialization format known as XMI based on XML, but there are many other concrete formats such
155+
as Xcore (a DSL built with Xtext, annotated Java, Json, binary serialization formats, the Rgen score
156+
DSL in Ruby, etc.)
157+

0 commit comments

Comments
 (0)