Permalink
Browse files

Add part three of the object series article.

  • Loading branch information...
1 parent 0070c3c commit 9bf2f0e1c16ce0c32f79f2fde7e683dee41dec24 @creationix creationix committed Nov 9, 2010
View
2 articles/object-graphs-2.markdown
@@ -74,7 +74,7 @@ To use this, simply call the function with the desired parameters. Notice how w
Here is the object graph that results from this code. Notice that we have access to the two passed in anonymous objects via the hidden `[scope]` property of the functions. Or in other words, we have access to `model` and `view` from the closure created by the factory function.
-![classical](object-graphs-2/factory.dot)
+![factory](object-graphs-2/factory.dot)
<br style="clear:left"/>
View
173 articles/object-graphs-3.markdown
@@ -0,0 +1,173 @@
+Title: Learning Javascript with Object Graphs (Part III)
+Author: Tim Caswell
+Date: Sat Oct 16 2010 07:40:03 GMT-0700 (PDT)
+Node: v0.2.3
+
+Part I of this series explained basic object graphs and visually described references, closures, and basic inheritance in JavaScript. Part II compared different styles for doing object-oriented programming in JavaScript. Now in Part III we'll get creative and look as Ruby's object model and compare it to how JavaScript works. Also I'll show how to implement some Ruby style classes. JavaScript is a very flexible language and can support about any object model you want with enough understanding and creativity.
+
+## Why Ruby
+
+Ok, I'll admit, I used to be a ruby guy. I didn't so much do rails, but I loved the ruby language. I read the pickaxe book, attended dallasrb, tried to start my own ruby based company, failed, and finally taught ruby to home-school kids.
+
+Also I chose ruby because I've noticed that several newcomers to the node.js community come from ruby and other languages with similar object systems. They often have a hard time adjusting to the simple, but new semantics of a language that looks like C/Java/PHP, but acts more like Lisp/Closure/Self.
+
+## What are Objects
+
+Both languages are object oriented languages. The difference is one subscribes to the stricter and slightly more complicated classical OO style while the other has a plain prototypal object system. In both languages all values are objects (or at least act like them). A ruby class is also an object who is an instance of the class `Class`. In JavaScript functions are also objects. In both primitive values like numbers and booleans are objects that contain methods/functions through their classes/prototypes. An object is simply a value that contains state and/or behavior through named channels. Objects provide encapsulation so that you can call `obj.save()` instead of having to use some external function and pass around all the state `save(obj)`.
+
+## Methods verses Functions
+
+Probably the biggest difference between the object models when you get down to it and ignore syntax is the fact that Ruby has methods and JavaScript has first-class functions. I can hear you thinking how "Wait, I thought 'method' and 'function' were synonyms!" so I'll explain what I mean.
+
+### Gotta keep them separated
+
+In classical OO, there is this idea that you must separate function from state. The same object structure can't hold both data and executable code. So classes hold the methods and instance objects hold the data (instance variables). Ruby is no exception. The language simply doesn't allow for methods on anything other than a class. Sure you can add singleton methods to objects, but the methods aren't actually on the object itself they are on a separate singleton class created just for the purpose of holding the methods for that single object.
+
+In JavaScript there is no concept of methods. Functions are first-class, meaning they are expressions just like `true`, `42`, `{}`, and everything else you can assign to a variable or property of an object. You can emulate classes if you explicitly put all your function properties in a shared prototype object and then have your "instance" objects all inherit from that common prototype, but the fact is you're not forced to work this way. For better or for worse, JavaScript has very few rules about what you can and can't do.
+
+### Controlled Inheritance
+
+Another side effect of this difference in inheritance. In Ruby and other classical OO languages, only methods can be inherited. Instance variables only exist on instances and instances can't inherit from instances, only classes inherit from classes. In JavaScript, any object can inherit from any object and all properties are subject to this prototypal inheritance no matter their type.
+
+### `self` and `this`
+
+Both languages have seemingly similar special variables that give you access to the current "scope".
+
+In Ruby `self` is the default receiver of all method calls that don't specify a receiver. In methods it's usually the instance object itself (or it's singleton class actually). You can't get at instance variable directly via `self`, but use the `@foo` notation instead. Any method invocation without an explicit receiver will get looked up in `self` and it's superclasses. Thus calling `foo()` is the exact same as calling `self.foo()`.
+
+In JavaScript, if you call `foo()` that's not the same thing at all as `this.foo()`. The first, `foo()` will look for a `foo` local variable via the closure and set it's `this` to `global`. But calling `this.foo()` will look for a `foo` property in `this` and call it with the old `this` as the new `this`.
+
+## Object Graphs
+
+Ok, enough theory, now for some sample code and diagrams! I'll show some ruby code, it's diagram, and then the closest JavaScript implementation I could think of and it's diagram.
+
+Most of the ruby examples are based on the MetaProgramming chapter of Programming Ruby 1.9 by Pragmatic Programmers.
+
+### A String
+
+All values are objects, let's start out with a simple string.
+
+#### Ruby
+
+<object-graphs-3/animal.rb>
+
+![animal.rb](object-graphs-3/animal.rb.dot)
+
+<br style="clear:left"/>
+
+Notice that every object has a class. Our string is of class `String` which inherits from the class `Object`. It's class `String` is of class `Class` which inherits `Module` and then `Object`.
+
+For purposes of seeing how `animal` works we don't need to worry about the classes of classes. The diagram is much simpler by removing that part:
+
+![animal.js](object-graphs-3/animal.rb.simple.dot)
+
+<br style="clear:left"/>
+
+Now you can clearly see what methods are available to our `animal` object.
+
+#### JavaScript
+
+<object-graphs-3/animal.js>
+
+![animal.js](object-graphs-3/animal.js.dot)
+
+<br style="clear:left"/>
+
+Remember that you can simulate classes in JavaScript using constructor + prototype pairs. That's just what the built-in object types do. The prototypes are objects and thus inherit directly from `Object.prototype` and the constructors are functions and inherit from `Function.prototype`.
+
+But let's see this diagram without the constructors, they don't affect the object once it's constructed and greatly complicate the image:
+
+![animal.js](object-graphs-3/animal.js.simple.dot)
+
+<br style="clear:left"/>
+
+That's much better. The literal `"cat"` inherits from the `String.prototype` which in turn inherits from `Object.prototype`. You can see why you're able to call functions like `animal.trim()` and see where the function comes from.
+
+### Singletons
+
+Remember that Ruby only allows methods on class objects. So what do you do if you really want to add a method to a single object? You'd have to create a special sub-class, add in the method you wanted, and then create your instance from that new class. Well, ruby has some nice syntax to make this easy and automatic:
+
+<object-graphs-3/singleton.rb>
+
+ # Output
+ The cat says miaow
+ CAT
+
+Let's see the graph of this object now that we added in a singleton method and class:
+
+![animal.js](object-graphs-3/singleton.rb.dot)
+
+<br style="clear:left"/>
+
+Notice that it injected a new anonymous class directly in front of the object and put the new method there for you. This class is hidden though. If you call the `animal.class()` then you'll get a reference to `String` directly.
+
+In JavaScript there is no need to create a new object to hold the function since the language allows functions to be stored anywhere. You simply assign the function directly to the object. There is one gotcha though. Primitives are immutable in JavaScript meaning you can't just add some properties to a string. This will work for any mutable object though so we'll use a regular expression instead.
+
+<object-graphs-3/singleton.js*>
+
+![animal.js](object-graphs-3/singleton.js.dot)
+
+<br style="clear:left"/>
+
+Notice that we just added the `speak` function in with the existing properties of the object. There is no need to separate them out into a different layer in JavaScript.
+
+### A Class
+
+Lets start out with a simple user-defined class and slowly add in inheritance, class methods, and mixed-in modules.
+
+First a simple user-defined class:
+
+<object-graphs-3/dave.rb>
+
+![animal.js](object-graphs-3/dave.rb.dot)
+
+<br style="clear:left"/>
+
+In JavaScript this is simply a constructor function: (Which is really just another function)
+
+<object-graphs-3/dave.js>
+
+![animal.js](object-graphs-3/dave.js.dot)
+
+<br style="clear:left"/>
+
+Notice that the prototype object was created for us and the linking back and forth was built-in. This is part of the ECMA spec. All functions, no matter if they are used as constructors or not, have a prototype.
+
+### Class Methods
+
+Since a class is an object, it's possible to give it singleton methods in Ruby and have what's known as class methods.
+
+<object-graphs-3/dave2.rb>
+
+ # Output
+ #<Dave:0x0000010086d3b8>
+ #<Dave:0x0000010086d340>
+ Hello
+
+
+![animal.js](object-graphs-3/dave2.rb.dot)
+
+<br style="clear:left"/>
+
+You see that it inserted a new anonymous class in the chain to store the `create` method.
+
+In JavaScript you can do the same by simply adding a property on the constructor:
+
+<object-graphs-3/dave2.js*>
+
+![animal.js](object-graphs-3/dave2.js.dot)
+
+<br style="clear:left"/>
+
+Here we make the constructor inherit from it's parent constructor (so that "class methods" get inherited) and inherit the prototypes so that "instance methods" get inherited. Again there is no need for hidden classes since javascript allows storing function properties on any object.
+
+## Moving Forward
+
+Originally I wanted this article to explore how to implement Ruby modules and mixing in javascript, but life got in the way. I started an awesome job at Palm working on node for webOS and moving to a new house. Also I hit a technical wall where I can't fully implement ruby style module includes because it's not possible in JavaScript. (I can't make new methods added to an already included module appear in all the prototype chains that include that module)
+
+So instead of holding onto this useful article for ages, I'm realeasing it as is. Hopefully when things settle down I can write the next part of the series.
+
+
+
+
+
View
77 articles/object-graphs-3/Class.js
@@ -0,0 +1,77 @@
+// Reimplementation of rb_include_module() from Ruby 1.9
+function includeModule(klass, module) {
+ Object.getOwnPropertyNames(module).forEach(function (name) {
+ Object.defineProperty(klass, name, Object.getPropertyDescriptor(module, name));
+ });
+ return klass;
+}
+
+// Reimplementation of rb_singleton_class() from Ruby 1.9
+function singletonClass(obj) {
+ var singleton = obj.__proto__;
+ if (!singleton.__singleton__) {
+ singleton = {};
+ Object.defineProperty(singleton, {__singleton__: {value: true}});
+ singleton.__proto__ = obj.__proto__;
+ obj.__proto__ = singleton;
+ }
+ return singleton;
+}
+
+// Port of rb_extend_object() from Ruby 1.9
+function extendObject(obj, module) {
+ return includeModule(singletonClass(obj), module);
+}
+
+function isClass(klass) {
+ return typeof klass === 'function'
+ && klass.hasOwnProperty('prototype')
+ && klass.prototype.hasOwnProperty('constructor')
+ && klass.prototype.constructor === klass;
+}
+
+module.exports = {
+ name: "Class",
+ // Dummy no-op initialize
+ initialize: function initialize() {},
+ // Create a new instance, but call the initializer if it exists
+ new: function _new() {
+ var obj = this.allocate();
+ obj.initialize.apply(obj, arguments);
+ return obj;
+ },
+ // Create a new instance, but skip initialize
+ allocate: function allocate() {
+ var obj = {};
+ obj.__proto__ = this;
+ return obj;
+ },
+ // This is to create a subclass, we don't have the < syntax like ruby
+ extend: function extend(name, child) {
+ child.__proto__ = this;
+ child.name = name;
+ return child;
+ },
+ // Make a shallow copy of some other object and insert it in the inheritance chain
+ mixin: function include(other) {
+ var props = {};
+ Object.getOwnPropertyNames(other).forEach(function (key) {
+ props[key] = Object.getOwnPropertyDescriptor(other, key);
+ });
+ var shim = Object.create(this.__proto__, props);
+ this.__proto__ = shim;
+ return this;
+ },
+ get ancestors(useRaw) {
+ var parents = [];
+ var current = this;
+ while (current = current.__proto__) {
+ if (useRaw) {
+ parents.push(current);
+ } else {
+ parents.push(current.name || current.constructor.name);
+ }
+ }
+ return parents;
+ }
+};
View
28 articles/object-graphs-3/Enumerable.js
@@ -0,0 +1,28 @@
+// This is a module that can be mixed into any prototype
+module.exports = {
+ name: "Enumerable",
+ // Implements a forEach much like the one for Array.prototype.forEach.
+ forEach: function forEach(callback, thisObject) {
+ var keys = Object.keys(this),
+ length = keys.length;
+ for (var i = 0; i < length; i++) {
+ var key = keys[i];
+ callback.call(thisObject, this[key], key, this);
+ }
+ },
+ // Implements a map much like the one for Array.prototype.map.
+ // Returns a normal Array instance.
+ map: function map(callback, thisObject) {
+ var keys = Object.keys(this),
+ length = keys.length,
+ accum = new Array(length);
+ for (var i = 0; i < length; i++) {
+ var key = keys[i];
+ accum[i] = callback.call(thisObject, this[key], key, this);
+ }
+ return accum;
+ },
+ get length() {
+ return Object.keys(this).length;
+ }
+};
View
1 articles/object-graphs-3/animal.js
@@ -0,0 +1 @@
+var animal = "cat";
View
47 articles/object-graphs-3/animal.js.dot
@@ -0,0 +1,47 @@
+digraph finite_state_machine {
+ size="8.2,5"
+ rankdir = "LR"
+
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[ Scope ]|<animal>animal"]
+
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ StringProto [label = "<__proto__>String.prototype|<constructor>constructor|<concat>concat|<trim>trim|…"];
+ FunctionProto [label = "<__proto__>Function.prototype|<constructor>constructor|<call>call|<apply>apply|…"];
+ ObjectProto [label = "<__proto__>Object.prototype|<constructor>constructor|<toString>toString|<valueOf>valueOf|…"];
+
+ /* Function Objects */
+ node [shape = Mrecord, fillcolor=orange, style=filled];
+ String [label = "<__proto__>String|<prototype>prototype|<fromCharCode>fromCharCode|…"];
+ Function [label = "<__proto__>Function|<prototype>prototype|…"];
+ Object [label = "<__proto__>Object|<prototype>prototype|<keys>keys|<create>create|…"];
+
+
+ /* Literals */
+ node [shape = plaintext, fillcolor=gray92, style="filled,rounded"];
+ cat [label="\"cat\""]
+
+ /* References */
+ top:animal -> cat;
+ StringProto:constructor -> String:__proto__;
+ FunctionProto:constructor -> Function:__proto__;
+ ObjectProto:constructor -> Object:__proto__;
+ String:prototype -> StringProto:__proto__;
+ Function:prototype -> FunctionProto:__proto__;
+ Object:prototype -> ObjectProto:__proto__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ cat -> StringProto:__proto__;
+ String:__proto__ -> FunctionProto:__proto__;
+ Object:__proto__ -> FunctionProto:__proto__;
+ Function:__proto__ -> FunctionProto:__proto__;
+ FunctionProto:__proto__ -> ObjectProto:__proto__;
+ StringProto:__proto__ -> ObjectProto:__proto__;
+
+
+
+
+}
View
29 articles/object-graphs-3/animal.js.simple.dot
@@ -0,0 +1,29 @@
+digraph finite_state_machine {
+ size="8,2.8"
+ rankdir = "LR"
+
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[ Scope ]|<animal>animal"]
+
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ StringProto [label = "<__proto__>String.prototype|concat|trim|substring|indexOf|replace|split|…"];
+ ObjectProto [label = "<__proto__>Object.prototype|toString|toLocaleString|hasOwnProperty|valueOf|isPrototypeOf|propertyIsEnumerable|…"];
+
+ /* Literals */
+ node [shape = plaintext, fillcolor=gray92, style="filled,rounded"];
+ cat [label="\"cat\""]
+
+ /* References */
+ top:animal -> cat;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ cat -> StringProto:__proto__;
+ StringProto:__proto__ -> ObjectProto:__proto__;
+
+
+
+
+}
View
1 articles/object-graphs-3/animal.rb
@@ -0,0 +1 @@
+animal = "cat"
View
37 articles/object-graphs-3/animal.rb.dot
@@ -0,0 +1,37 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+
+ /* Variables */
+ node [shape=none,fillcolor=white];
+ animal;
+
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ cat [label = "<value>value: \"cat\"|<class>class"];
+
+ /* Classes */
+ node [shape = Mrecord, fillcolor=yellow, style=filled];
+ String [label="<__self__>String|<class>class|downcase()|upcase()|…"];
+ Object [label="<__self__>Object|<class>class|clone()|dup()|…"];
+ Class [label="<__self__>Class|<class>class|allocate()|new()|superclass()"];
+ Module [label="<__self__>Module|<class>class|ancestors()|instance_methods()|class_variables()|…"];
+
+
+
+ /* References */
+ cat:class -> String:__self__;
+ String:class -> Class:__self__;
+ Object:class -> Class:__self__;
+ Class:class -> Class:__self__;
+ Module:class -> Class:__self__;
+ animal -> cat:value;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ String:__self__ -> Object:__self__;
+ Class:__self__ -> Module:__self__;
+ Module:__self__ -> Object:__self__;
+
+}
View
26 articles/object-graphs-3/animal.rb.simple.dot
@@ -0,0 +1,26 @@
+digraph finite_state_machine {
+ size="8,3"
+ rankdir = "LR"
+
+
+ /* Variables */
+ node [shape=none,fillcolor=white];
+ animal;
+
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ cat [label = "<value>value: \"cat\"|<class>class"];
+
+ /* Classes */
+ node [shape = Mrecord, fillcolor=yellow, style=filled];
+ String [label="<__self__>String|casecmp()|match()|downcase()|upcase()|unpack()|reverse()|…"];
+ Object [label="<__self__>Object|class()|clone()|dup()|freeze()|taint()|trust()|…"];
+
+ /* References */
+ cat:class -> String:__self__;
+ animal -> cat:value;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ String:__self__ -> Object:__self__;
+}
View
0 articles/object-graphs-3/class.rb
No changes.
View
1 articles/object-graphs-3/dave.js
@@ -0,0 +1 @@
+function Dave() {}
View
36 articles/object-graphs-3/dave.js.dot
@@ -0,0 +1,36 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ DaveProto [label = "<__proto__>Dave.prototype|<constructor>constructor"];
+ FunctionProto [label = "<__proto__>Function.prototype|<constructor>constructor|<call>call|<apply>apply|…"];
+ ObjectProto [label = "<__proto__>Object.prototype|<constructor>constructor|<toString>toString|<valueOf>valueOf|…"];
+
+ /* Function Objects */
+ node [shape = Mrecord, fillcolor=orange, style=filled];
+ Dave [label = "<__proto__>Dave|<prototype>prototype"];
+ Function [label = "<__proto__>Function|<prototype>prototype|…"];
+ Object [label = "<__proto__>Object|<prototype>prototype|<keys>keys|<create>create|…"];
+
+ /* References */
+ DaveProto:constructor -> Dave:__proto__;
+ FunctionProto:constructor -> Function:__proto__;
+ ObjectProto:constructor -> Object:__proto__;
+ Dave:prototype -> DaveProto:__proto__;
+ Function:prototype -> FunctionProto:__proto__;
+ Object:prototype -> ObjectProto:__proto__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ Dave:__proto__ -> FunctionProto:__proto__;
+ Object:__proto__ -> FunctionProto:__proto__;
+ Function:__proto__ -> FunctionProto:__proto__;
+ FunctionProto:__proto__ -> ObjectProto:__proto__;
+ DaveProto:__proto__ -> ObjectProto:__proto__;
+
+
+
+
+}
View
2 articles/object-graphs-3/dave.rb
@@ -0,0 +1,2 @@
+class Dave
+end
View
24 articles/object-graphs-3/dave.rb.dot
@@ -0,0 +1,24 @@
+digraph finite_state_machine {
+ size="8,2.4"
+ rankdir = "LR"
+
+
+ /* Classes */
+ node [shape = Mrecord, fillcolor=yellow, style=filled];
+ Dave [label="<__self__>Dave|<class>class|…"];
+ Object [label="<__self__>Object|<class>class|clone()|dup()|…"];
+ Class [label="<__self__>Class|<class>class|allocate()|new()|superclass()"];
+ Module [label="<__self__>Module|<class>class|ancestors()|instance_methods()|class_variables()|…"];
+
+
+
+ /* References */
+ Dave:class -> Class:__self__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ Dave:__self__ -> Object:__self__;
+ Class:__self__ -> Module:__self__;
+ Module:__self__ -> Object:__self__;
+
+}
View
19 articles/object-graphs-3/dave2.js
@@ -0,0 +1,19 @@
+// Make a parent class
+function Person() {}
+// with an instance method
+Person.prototype.greet = function greet() {
+ console.log("Hello");
+}
+// and a class method.
+Person.create = function create() {
+ return new this();
+};
+
+// Create a subclass
+function Dave() {}
+Dave.__proto__ = Person;
+Dave.prototype.__proto__ = Person.prototype;
+// and test it.
+console.log(Dave.create());
+console.log(new Dave);
+Dave.create().greet();
View
42 articles/object-graphs-3/dave2.js.dot
@@ -0,0 +1,42 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ PersonProto [label = "<__proto__>Person.prototype|<constructor>constructor|<greet>greet"];
+ DaveProto [label = "<__proto__>Dave.prototype|<constructor>constructor"];
+ FunctionProto [label = "<__proto__>Function.prototype|<constructor>constructor|<call>call|<apply>apply|…"];
+ ObjectProto [label = "<__proto__>Object.prototype|<constructor>constructor|<toString>toString|<valueOf>valueOf|…"];
+
+ /* Function Objects */
+ node [shape = Mrecord, fillcolor=orange, style=filled];
+ Dave [label = "<__proto__>Dave|<prototype>prototype"];
+ Person [label = "<__proto__>Person|<prototype>prototype|<create>create"];
+ Function [label = "<__proto__>Function|<prototype>prototype|…"];
+ Object [label = "<__proto__>Object|<prototype>prototype|<keys>keys|<create>create|…"];
+
+ /* References */
+ DaveProto:constructor -> Dave:__proto__;
+ PersonProto:constructor -> Person:__proto__;
+ FunctionProto:constructor -> Function:__proto__;
+ ObjectProto:constructor -> Object:__proto__;
+ Person:prototype -> PersonProto:__proto__;
+ Dave:prototype -> DaveProto:__proto__;
+ Function:prototype -> FunctionProto:__proto__;
+ Object:prototype -> ObjectProto:__proto__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ DaveProto:__proto__ -> PersonProto:__proto__;
+ FunctionProto:__proto__ -> ObjectProto:__proto__;
+ PersonProto:__proto__ -> ObjectProto:__proto__;
+ Person:__proto__ -> FunctionProto:__proto__;
+ Object:__proto__ -> FunctionProto:__proto__;
+ Function:__proto__ -> FunctionProto:__proto__;
+ Dave:__proto__ -> Person:__proto__;
+
+
+
+
+}
View
19 articles/object-graphs-3/dave2.rb
@@ -0,0 +1,19 @@
+# Make a parent class
+class Person
+ # with an instance method
+ def greet
+ puts "Hello"
+ end
+ # and a class method.
+ def self.create
+ self.new
+ end
+end
+
+# Create a subclass
+class Dave < Person
+end
+# and test it.
+puts Dave.create
+puts Dave.new
+Dave.create.greet
View
25 articles/object-graphs-3/dave2.rb.dot
@@ -0,0 +1,25 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ /* Classes */
+ node [shape = Mrecord, fillcolor=yellow, style=filled];
+ Person [label="<__self__>Person|<class>class|greet()|…"];
+ PersonSingleton [label="<__self__>[anonymous]|create()"];
+ Dave [label="<__self__>Dave|<class>class|…"];
+ Object [label="<__self__>Object|<class>class|clone()|dup()|…"];
+ Class [label="<__self__>Class|<class>class|allocate()|new()|superclass()"];
+ Module [label="<__self__>Module|<class>class|ancestors()|instance_methods()|class_variables()|…"];
+
+ /* References */
+ Person:class -> PersonSingleton:__self__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ Dave:__self__ -> Person:__self__;
+ Person:__self__ -> Object:__self__;
+ PersonSingleton:__self__ -> Class:__self__;
+ Class:__self__ -> Module:__self__;
+ Module:__self__ -> Object:__self__;
+
+}
View
7 articles/object-graphs-3/singleton.js
@@ -0,0 +1,7 @@
+var animal = /cat/;
+
+animal.speak = function speak() {
+ console.log("The " + this + " says miaow");
+};
+animal.speak();
+animal.test('caterpiller');
View
26 articles/object-graphs-3/singleton.js.dot
@@ -0,0 +1,26 @@
+digraph finite_state_machine {
+ size="8,2.6"
+ rankdir = "LR"
+
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[ Scope ]|<animal>animal"]
+
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ RegExpProto [label = "<__proto__>RegExp.prototype|exec|compile|test|toString|…"];
+ ObjectProto [label = "<__proto__>Object.prototype|toString|toLocaleString|hasOwnProperty|valueOf|isPrototypeOf|…"];
+ cat [label = "<__proto__>\/cat\/|speak|lastIndex|source|multiline|…"];
+
+ /* References */
+ top:animal -> cat:__proto__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ cat:__proto__ -> RegExpProto:__proto__;
+ RegExpProto:__proto__ -> ObjectProto:__proto__;
+
+
+
+
+}
View
6 articles/object-graphs-3/singleton.rb
@@ -0,0 +1,6 @@
+animal = "cat"
+def animal.speak
+ puts "The #{self} says miaow"
+end
+animal.speak
+puts animal.upcase
View
28 articles/object-graphs-3/singleton.rb.dot
@@ -0,0 +1,28 @@
+digraph finite_state_machine {
+ size="8,3"
+ rankdir = "LR"
+
+
+ /* Variables */
+ node [shape=none,fillcolor=white];
+ animal;
+
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ cat [label = "<value>value: \"cat\"|<class>class"];
+
+ /* Classes */
+ node [shape = Mrecord, fillcolor=yellow, style=filled];
+ catSingleton [label="<__self__>[anonymous]|speak()"];
+ String [label="<__self__>String|casecmp()|match()|downcase()|upcase()|unpack()|reverse()|…"];
+ Object [label="<__self__>Object|class()|clone()|dup()|freeze()|taint()|trust()|…"];
+
+ /* References */
+ cat:class -> catSingleton:__self__;
+ animal -> cat:value;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ catSingleton:__self__ -> String:__self__;
+ String:__self__ -> Object:__self__;
+}
View
17 articles/object-graphs-3/test.js
@@ -0,0 +1,17 @@
+var Class = require('./class'),
+ Enumerable = require('./enumerable');
+
+var Foo = Class.extend("Foo", {
+ greet: function greet() {
+ console.log("Hello World");
+ }
+});
+Foo.mixin(Enumerable);
+
+var f = Foo.new();
+f.greet();
+f.age = 28;
+f.height = 12 * 6 + 4;
+console.dir(f.map(function (key, value) { return key + " = " + value; }));
+console.dir(f.ancestors);
+console.dir(f.length);
View
32 articles/object-graphs/shared-function.dot
@@ -0,0 +1,32 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ /* Functions */
+ node [shape = Mrecord, fillcolor=orange, style=filled];
+ global [label="<Lane>Lane|<descr>descr|<Fred>Fred|<description>description"];
+ fn1 [label="<__proto__>Function"];
+ fn2 [label = "<__proto__>Function|<name>name"];
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightBlue, style=filled];
+ obj1 [label = "<__proto__>Object|<name>name | <description> description"];
+ obj2 [label = "<__proto__>Object|<descr> descr | <name>name"];
+ obj3 [label = "<__proto__>Object|<name>name"];
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ name [label="\"Lane the Lambda\""]
+ name2 [label="\"Fred the Functor\""]
+ name3 [label="\"Zed the Zetabyte\""]
+ name4 [label="\"Cloe the Closure\""]
+
+ global:Lane -> obj1:__proto__;
+ obj1:name -> name;
+ obj1:description -> fn1;
+ global:Fred -> obj2:__proto__;
+ obj2:name -> name2;
+ obj2:descr -> fn1:__proto__;
+ obj3:name -> name3;
+ global:descr -> fn1:__proto__;
+ global:description -> fn2:__proto__;
+ fn2:name -> name4;
+}

0 comments on commit 9bf2f0e

Please sign in to comment.