├── Anders-font ├── .DS_Store ├── Anders.eot ├── Anders.svg ├── Anders.ttf ├── Anders.woff └── styles.css ├── CNAME ├── README.md ├── index.html ├── main.css ├── prism.css ├── prism.js ├── sidebar.css └── sidebar.js /Anders-font/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlfriess/eiffel-guide/ad0f6e19f0d0d204cae892b528464c6cfe3d8786/Anders-font/.DS_Store -------------------------------------------------------------------------------- /Anders-font/Anders.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlfriess/eiffel-guide/ad0f6e19f0d0d204cae892b528464c6cfe3d8786/Anders-font/Anders.eot -------------------------------------------------------------------------------- /Anders-font/Anders.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1931 | -------------------------------------------------------------------------------- /Anders-font/Anders.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlfriess/eiffel-guide/ad0f6e19f0d0d204cae892b528464c6cfe3d8786/Anders-font/Anders.ttf -------------------------------------------------------------------------------- /Anders-font/Anders.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlfriess/eiffel-guide/ad0f6e19f0d0d204cae892b528464c6cfe3d8786/Anders-font/Anders.woff -------------------------------------------------------------------------------- /Anders-font/styles.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face { 3 | font-family: 'Anders'; 4 | src: url('Anders.eot?#iefix') format('embedded-opentype'), url('Anders.woff') format('woff'), url('Anders.ttf') format('truetype'), url('Anders.svg#Anders') format('svg'); 5 | font-weight: normal; 6 | font-style: normal; 7 | } 8 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | eiffel-guide.com -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A comprehensive guide to Eiffel syntax 2 | 3 | This is a website guide about the Eiffel programming language. It is designed to be a basic reference to help beginners get acquainted with the language. Please help improve and maintain this website through GitHub. 4 | 5 | http://eiffel-guide.com/ 6 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |Welcome to this guide about the Eiffel programming language. It is designed to be a basic reference to help beginners get acquainted with the language. Some knowledge of other programming languages might be considered very useful. This should not be seen as a course or tutorial. Please help improve and maintain this page through GitHub. To get started, let's have a look at this simple hello world:
31 | 32 |
33 | class
34 | HELLO_WORLD
35 |
36 | create
37 | say_it
38 |
39 | feature
40 | say_it
41 | do
42 | Io.put_string ("Hello World!")
43 | end
44 |
45 | end
46 |
Hello World!
The first difference you will notice in Eiffel compared to other languages like C++ or Java is the absence of curly brackets to separate code blocks. Instead in Eiffel we use keywords followed by end. We also do not ordinarily terminate lines of code with a semi-colon. However, it is acceptable to separate statements with a semi-colon if you so wish. Features (functions) are called without using brackets, if they do not accept any arguments (e.g. target.my_function instead of target.my_function()). 54 | 55 | 56 | 57 |
In general, in Eiffel we use snake_script and not CamelCase.
60 | 61 |CLASSES should be spelled in capital letters.
62 |features (methods and attributes of classes) should be spelled small.
63 |Objects (instances of a class) should be capitalised.
64 | 65 | 66 | 67 |In Eiffel, the Methods and Attributes (Variables) of a class are called features. We can define them by using the keyword feature followed by the features name within a class. We specify the features type or return type by using a colon followed by the types name. If a feature is a function and takes arguments we can list them in brackets together with their types. The keyword do is used to denote where the code of the function starts, followed by end at the end.
70 | 71 |
72 |
73 | class
74 | BAKERY
75 |
76 | feature
77 |
78 | number_of_cakes : INTEGER
79 | -- A variable containing an integer
80 |
81 | name_of_my_favourite_cake : STRING
82 | -- A variable containing a string
83 |
84 | price_of_one_cake : REAL
85 | -- A variable containing a floating point number
86 |
87 | buy_cake (price : REAL; flavour : STRING) -- A function accepting arguments
88 | do
89 | -- Some code here...
90 | end
91 |
92 | is_cake_available : BOOLEAN -- A function returning true or false
93 | do
94 | Result := number_of_cakes > 0
95 | end
96 |
97 | end
98 |
99 |
The return value of a feature is set by assigning it to the Result variable. Unlike other languages, the return statement does not exist. 102 | 103 |
Also notice that, when defining a feature, arguments are separated using semi-colons. However, when calling the feature, they are separated by means of a comma.
104 | 105 |Features may also use local variables which are internal to the function. However, they must be declared with their type before the do keyword using the local keyword. For example:
106 | 107 |
108 |
109 | class
110 | MY_CLASS
111 | feature
112 | my_feature
113 | local
114 | my_variable_1 : INTEGER
115 | my_variable_2 : STRING
116 | do
117 | -- Some code here...
118 | end
119 | end
120 |
121 |
The variables of a class are read-only to its clients. To change their values, we can use a setter, a feature that takes the new value as an argument, like in the case of set_age below:
128 | 129 |
130 |
131 | class
132 | PERSON
133 | feature
134 | age: INTEGER
135 | set_age ( new_age: INTEGER )
136 | do
137 | age := new_age
138 | end
139 | end
140 |
141 |
So, a client of the class would not be able to change the age by using Person.age := 21, as Person.age is read-only for clients. Instead it would call Person.set_age(21). However, if for some reasons you are feeling radical and want to use Person.age := 21, you can give age a so called assigner by using the assign keyword and specifying a setter.
144 | 145 |
146 |
147 | class
148 | PERSON
149 | feature
150 | age: INTEGER assign set_age
151 | set_age ( new_age: INTEGER )
152 | do
153 | age := new_age
154 | end
155 | end
156 |
157 |
Now, Person.age := 21 is simply a shortcut for Person.set_age(21).
160 | 161 | 162 | 163 |Although quite rarely used, in Eiffel a feature can be specified to only be executed once then save its return value and simply return it immediately at every subsequent call. To do this, simply use the once keyword instead of do.
166 | 167 |
168 |
169 | feature
170 | first_name: STRING
171 | last_name: STRING
172 | full_name: STRING
173 | once
174 | first_name := "John"
175 | last_name := "Doe"
176 | Result := first_name + " " + last_name
177 | end
178 |
179 |
This can be useful for initialisation. A setup feature could implement the initialisation of an object but be called from multiple other features. By using once, we can guarantee that it will only perform the initialisation once regardless of who calls it and how many times it is called. 182 | 183 |
It is also possible to specify in which context the feature should be considered as called. This is particularly important when using multiple threads or processes. For instance, you may want to execute a feature only once for each Process, once for each Thread or for every object instance. To specify this, use the once keys "PROCESS", "THREAD" and "OBJECT". These are specified as strings and in brackets after the once keyword like so: once ("PROCESS"). The default once key is "THREAD".
184 | 185 | 186 | 187 |The simplest way to define a class in Eiffel is just to name it and give it some features. It may even inherit features from other classes. For this we can list all of the desired classes after stating the inherit keyword. Using the redefine keyword features may be specified for classes that should be redefined in this class and not inherited.
190 | 191 |
192 |
193 | class
194 | MY_CLASS
195 |
196 | inherit
197 | SOME_OTHER_CLASS
198 | redefine
199 | some_inherited_feature
200 | end
201 |
202 | feature
203 | some_feature
204 | do
205 | [...]
206 | end
207 | some_inherited_feature
208 |
209 | [...]
210 |
211 | end
212 |
213 |
When redefining a feature, it can be helpful to call its old version. So, within the redefinition, the keyword Precursor is set to the old version and calls can be made like this: Precursor("Some argument"). If you would like to use a version from a specific parent, you can add curly brackets: Precursor { SOME_PARENT } ("Some argument")
216 | 217 |In the case of MY_CLASS, when we want to create an instance of the class, we first need to define the object and specify its type. Then, we use the create keyword to initialise the object, before making other calls to it. A client of the class might look like this:
218 | 219 |
220 |
221 | feature
222 | example
223 | local
224 | New_object: MY_CLASS
225 | do
226 | create New_object
227 | New_object.some_feature
228 | end
229 |
230 |
In Eiffel there is a key differentiation between reference and expanded classes. By default a class is of the reference type. To declare a class as expanded, we use the expanded keyword before class.
237 | 238 |As the name would suggest a reference class sets itself apart in that its attributes are references to other objects, either of classes defined by the developer or built-in classes such as STRING or REAL. As such, an object of a the reference type does not contain any actual values apart from addresses. It only contains references to where the values are stored in the memory. In C or C++ references would be referred to as pointers. An expanded class on the other hand does not contain references, but the actual values. This key difference has an effect on how we create and use classes.
239 | 240 |Another difference, is that when used as an argument, data of an expanded type is passed by value, while data of reference types are passed by reference, since the object consists of addresses.
241 | 242 | 243 | 244 |When we define an object of a certain class, the computer will allocate memory to hold that class's attributes. However, in the case of a reference class, this allocated memory will only hold the references or addresses to the objects containing the actual values. So by default all attributes of a class will be set to Void, as the objects that the class refers to, do not exist yet. To create these we must always call create before using a new instance.
247 | 248 |It is possible to test if an object x has been initialised yet by using the expression x = Void.
249 | 250 |It is good style to use constructors to initialise attributes to the correct values and ensure that any class invariants are fulfilled. To enforce the use of constructors, we can specify features as possible constructors using the create keyword like so:
251 | 252 |
253 |
254 | class
255 | MY_CLASS
256 | create
257 | my_feature
258 | feature
259 | my_feature (some_argument : STRING)
260 | do
261 | -- Do something here...
262 | end
263 | end
264 |
265 |
An instance my_object of the class would then be initialised like so:
268 | 269 |
270 |
271 | create my_object.my_feature("Hello World!")
272 |
273 |
You may specify as many constructors as you want. However, as soon as at least one constructor has been specified, a constructor must be used when creating a new instance. If no constructors are specified, then simply creating an object without adding a constructor will invoke default_create, which is a feature that is automatically added to every class without constructors and by default does nothing.
276 | 277 | 278 | 279 |Expanded classes differ from reference classes in that they do not contain references, but rather the actual values of their attributes. For this reason, we do not need to call create before using objects that are instances of the class. All attributes are automatically set to their default initial values when the object is defined.
282 | 283 |If a and b are both instances of an expanded class, a := b will copy all of b (including its values) into a and create a new instance with the same values.
284 | 285 |On the other hand, if a and b are both instances of a reference class, then a := b will copy the reference to the instance of the class represented by b into a. In other words, now a and b will reference the same instance and any change to a will be reflected in b.
286 | 287 | 288 | 289 |By default all features defined in a class will be available to clients of the class. To prevent this, we can use {NONE} to keep features internal and inaccessible to clients. The Current keyword is considered a client. Hence, when using {NONE} for a feature, it will not be accessible using Current. This is similar to using private in Java for instance.
292 | 293 |In fact, in Eiffel we can be very specific about which features are available to which clients, by specifying the class a client must have in order to access the feature. For this we once again use the curly brackets and list all the desired classes like so:
294 | 295 |
296 |
297 | class
298 | A
299 | feature -- `s` will be available to all clients of the class.
300 | s
301 | ...
302 | feature {NONE} -- `u` and `v` will only be available internally.
303 | u, v
304 | ...
305 | feature {A, B} -- `x` will only be available to clients of the same type
306 | x -- and to clients of the type `B`.
307 | ...
308 | feature {C} -- `y` and `z` will be available only to clients of the type C.
309 | y, z
310 | ...
311 | end
312 |
313 |
One more thing to consider is, that creation procedures are not considered qualified calls. Therefore, when using a feature as a constructor, where it is exported to does not apply. if you would like to still specify which features are available to which classes, you can use the same notation, but with the create declaration.
316 | 317 | 318 | 319 |Above we had a look at how classes can inherit and export features. Deferred classes have the capability to specify features without defining them, so that children of the class must themselves define them.
322 | 323 |As soon as a class contains at least one deferred feature, it must be declared as deferred (notice the deferred keyword before class). A feature can be declared as deferred by using the deferred keyword, followed immediately by the end statement. A deferred feature does not have to be declared as redefined in a child class.
324 | 325 |
326 |
327 | deferred class
328 | MY_CLASS
329 |
330 | feature
331 | some_feature: STRING
332 | another_feature
333 | deferred
334 | end
335 |
336 | end
337 |
338 |
When using a custom class to store data, it can be useful to use operators in order to compare objects of that class. For this we must define a feature that performs the comparison and is an alias for an operator. We use the alias keyword after the feature name to choose the operator. In this example, people will be compared according to their age:
345 | 346 |
347 |
348 | class
349 | PERSON
350 |
351 | feature
352 | name: STRING
353 | age: INTEGER
354 |
355 | older_than alias ">" (other: PERSON) : BOOLEAN
356 | do
357 | Result := (age > other.age)
358 | end
359 |
360 | end
361 |
362 |
If we now had an instance of the class called Joe with the age 36 and another called Tom with the age 24, then Joe > Tom is true, while Tom > Joe is false.
365 | 366 | 367 | 368 |We have already seen, that classes can inherit features from other classes and redefine them to change their behaviour. We have also seen that classes may defer features to be implemented in a child class. However, when inheriting from multiple classes we run into another problem: clashes.
371 | 372 |If a class C inherits from two classes A and B, which both have a feature called f then we will need to rename or undefine the feature for at least one of the two classes. For this we can use the rename and undefine keywords similarly to redefine. Consider the following implementation of the before mentioned problem:
373 | 374 |
375 |
376 | class
377 | A
378 |
379 | feature
380 | f
381 | do
382 | -- Some code...
383 | end
384 | g
385 | do
386 | -- Some code...
387 | end
388 |
389 | end
390 |
391 |
394 |
395 | class
396 | B
397 |
398 | feature
399 | f
400 | do
401 | -- Some different code...
402 | end
403 | g
404 | do
405 | -- Some different code...
406 | end
407 |
408 | end
409 |
410 |
413 |
414 | class
415 | C
416 |
417 | inherit
418 | A
419 | rename
420 | f as A_f -- The feature f inherited from A is now called A_f within C
421 | end
422 |
423 | B
424 | undefine
425 | g -- The feature g inherited from B is no longer part of C
426 | end
427 |
428 | feature
429 |
430 | ...
431 |
432 | end
433 |
434 |
In the above example, the feature f inherited from B is still called f in C, the same goes for the feature g inherited from A. So in conclusion, the class C now has the features A_f (inherited from A), f (inherited from B) and g (inherited from A).
437 | 438 |If the classes A and B were inheriting the features f and g from the same class instead of defining them themselves, then in fact there is no need to undefine or rename any of the features, as there is only one effective implementation for them. 439 | 440 | 441 | 442 |
These are some examples of basic input/output functions, that can be used to interact with a user at a command line level:
445 | 446 |Io.put_string ("Hello World!") Prints out a string
447 |Io.put_integer (42) Prints out an integer
448 |Io.put_real (9.99) Prints out a real
449 |Io.put_boolean (true) Prints out a true or false
450 |Io.new_line Prints out a new line
451 | 452 |Io.read_line Reads in one line of users input and stores it in Io.last_string
453 |Io.read_integer Reads in an integer from users input and stores it in Io.last_integer
454 | 455 | 456 | 457 |:= Assignment operator. Ex: meaning_of_life := 42
460 |= Equality operator (== in many other languages). Ex: 1 + 2 = 3 would be true
461 |/= Inequality operator (!= in many other languages). Ex: meaning_of_life /= 42
462 |<, >, <=, >= Comparison operators.
463 |+, -, *, / Mathematical operators.
464 |// Integer division operator. Ex: 5/2=2.5 vs 5//2=2
465 |\\ Modulo. Ex: 5\\2=1
466 |equal (x, y) To compare strings we can use the equal function.
467 |Current Though not an operator, this always references the currently executing instance of a class.
468 ||..| Describes an integer interval. Useful in loops. e.g. 1 |..| 5
469 |.. Describes an interval of integers or characters in inspect constructions. e.g. a .. z
470 |and, or, xor, not Logic operators.
471 |and then, or else, implies Semistrict logic operators (evaluation stops when the result is known).
472 | 473 | 474 | 475 |In Eiffel the syntax for an if/elseif/else structure is as follows (notice: there are no brackets, and no then following the else):
478 | 479 |
480 |
481 | if meaning_of_life = 42
482 | then
483 | -- code if true
484 | elseif meaning_of_life = 43
485 | then
486 | -- code if only second condition is true
487 | else
488 | -- code if all previous conditions are false
489 | end
490 |
491 |
Eiffel also provides switch-like Statements called inspect, where a variable is compared to various values. The else condition is the default condition that applies when no case matches the input.
494 | 495 |
496 |
497 | inspect input_integer
498 | when 2 then
499 | -- Code when input_integer equals 2
500 | when 3, 5 then
501 | -- Code when input_integer equals 3 or 5
502 | when 7..9 then
503 | -- Code when input_integer equals 7 or 8 or 9
504 | else
505 | -- Code when input_integer does not equal 2, 3, 5, 7, 8 nor 9
506 | end
507 |
508 |
Unlike switch statements in other languages, in Eiffel the code following a matching case is not evaluated and there is no break statement in Eiffel.
511 | 512 | 513 | 514 |This is the typical syntax for a simplified from loop (comparable to for loops in other languages):
517 | 518 |
519 |
520 | from
521 | i := 0
522 | until
523 | i >= 10
524 | loop
525 | -- do something
526 | i := i + 1
527 | end
528 |
529 |
Notice, that in Eiffel loops are evaluated until the conditional becomes true rather than while the conditional is true, which is common in most other languages (Ex. for-loop in C, Java, etc.).
532 | 533 |It is also possible to add contracts to a from loop. The two options here are to specify a variant expression and an invariant expression. The variant must decrease by at least 1 after each cycle of the loop, while the invariant remains the same. Here is an example:
534 | 535 |
536 |
537 | from
538 | i := 0
539 | n := 10
540 | invariant
541 | n > 0
542 | until
543 | i >= 10
544 | loop
545 | i := i + 1
546 | variant
547 | n-i
548 | end
549 |
550 |
The contracts in loops are designed to prevent bugs such as endless loops. As such the variant is supposed to be an estimation of the number of iterations. 553 | 554 |
There also exists an "across"-loop, which goes through an iterable object (such as a list), and creates a cursor. Make sure that the object is in fact iterable. For this all elements must have a feature called next and the iterated object should have the features first and last. The cursor points to the next element of the iterated object at each execution of the loop. Since it is a cursor, you must access the actual elements by using my_cursor.item.
555 | 556 |
557 |
558 | across list_of_customers as customer loop
559 | Io.put_string (customer.item.name)
560 | Io.new_line
561 | end
562 |
563 |
For instance, an integer interval is an iterable object.
566 | 567 |
568 |
569 | across 1 |..| 5 as it loop
570 | Io.put_integer (it.item)
571 | Io.new_line
572 | end
573 |
574 |
Contracts are a concept used in Eiffel to avoid bugs. Although these should be disabled in a production runtime, during development they can be quite useful. There are three types of assurance elements: preconditions (used in features), postconditions (used in features) and class invariants.
580 | 581 |Preconditions are defined using the require keyword. They should contain a tag and a boolean expression. Postconditions are written the same way, but we use the ensure keyword. We can use the old notation to compare a variable's value to its value before the feature was executed. Here is an example that might be used in the BAKERY class we saw above:
582 | 583 |
584 |
585 | number_of_available_cakes : INTEGER
586 |
587 | buy_cakes (amount : INTEGER)
588 |
589 | require
590 | positive_amount: amount > 0 -- Check that amount is a positive number
591 |
592 | do
593 | number_of_available_cakes = number_of_available_cakes - amount
594 |
595 | ensure
596 | amount_reduced: number_of_available_cakes = old number_of_available_cakes - amount
597 | -- Check that the number of available cakes has decreased correctly
598 |
599 | end
600 |
601 |
Class invariants are checked every time an operation is performed on the class, such as calling a feature. We declare class invariants using the invariant keyword. In this example we will check that a variable is always positive:
604 | 605 |
606 |
607 | class
608 | MY_CLASS
609 |
610 | feature
611 | some_number : INTEGER
612 | some_feature
613 | do
614 | -- Some code here...
615 | end
616 |
617 | invariant
618 | positive: some_number > 0
619 |
620 | end
621 |
622 |
This is a concept that is particularly useful when creating structures like lists. Using genericity we can define classes with generic types that can be specified later. Like this we can use the same class to make a list of strings and to make a list of integers for instance.
629 | 630 |To use this in a class, the we can specify a generic parameter (ex. G) in in square brackets after the class name like so class MY_CLASS [G]. Then when defining an object of this class er must specify which class to use for the generic type like this: my_object: MY_CLASS[ STRING ]. This is a more detailed example of a generic class:
631 | 632 |
633 |
634 | class MY_LIST [G] feature
635 |
636 | first : G
637 | last : G
638 | extend (new_element: G)
639 | do
640 | -- Add element to list...
641 | end
642 |
643 | end
644 |
645 |
648 |
649 | class SCHOOL feature
650 |
651 | list_of_students : MY_LIST[ STUDENT ]
652 | list_of_classes : MY_LIST[ MY_LIST[ STUDENT ] ]
653 |
654 | end
655 |
656 |
Particularly in event-driven programming, it can be useful to represent a feature using an object. For this we can use agents. We create an agent by using the agent keyword followed by the features we want to pass. To call the feature encapsulated by an agent object we use my_agent.call() if we expect no return value. To receive a return value we use my_agent.item() instead.
663 | 664 |The following example is similar to a situation that might occur when programming a GUI. When run, the application prints "The button was clicked!".
665 | 666 |
667 |
668 | class
669 | APPLICATION
670 |
671 | create
672 | run
673 |
674 | feature
675 |
676 | run
677 | local
678 | button : BUTTON
679 | do
680 | create button.set_click_handler( agent click_event )
681 | button.click
682 | end
683 |
684 | click_event
685 | do
686 | Io.put_string ("The button was clicked!")
687 | end
688 |
689 | end
690 |
691 |
694 |
695 | class
696 | BUTTON
697 |
698 | create
699 | set_click_handler
700 |
701 | feature
702 |
703 | click_handler : PROCEDURE [APPLICATION, TUPLE[]]
704 |
705 | set_click_handler ( handler: PROCEDURE [APPLICATION, TUPLE[]] )
706 | do
707 | click_handler := handler
708 | end
709 |
710 | click
711 | do
712 | click_handler.call
713 | end
714 |
715 | end
716 |
717 |
To pass arguments to the feature when calling it through an agent we pass a tuple (denoted by square brackets) with all the arguments when invoking the agent. For this to work, we must also change the creation of the agent. To pass three arguments, we would create the agent using my_agent := agent my_feature(?, ?, ?) and then call it with a.call([argument_1, argument_2, argument_3]).
720 | 721 |The type of an my_agent from above would be PROCEDURE[ T, TUPLE[ ARG1, ARG2, ARG3 ] ], where T is the class my_feature belongs to and ARG1, ARG2 and ARG3 are the types of argument_1, argument_2 and argument_3 respectively.
722 | 723 |If the encapsulated feature is to return a value, then the type is actually FUNCTION[ T, TUPLE[ ARG1, ARG2, ARG3 ], RETURN_TYPE ].
724 | 725 | 726 | 727 |Eiffel uses a garbage collector which automatically removes any objects from the memory when they are no longer referenced anywhere. So unlike in C or C++ for instance, it is not necessary to manage the memory.
730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | /* Main CSS */ 2 | 3 | body { 4 | margin: 0; 5 | padding: 0; 6 | background-color: #263238; 7 | } 8 | 9 | h1 { 10 | font-family: "Anders"; 11 | text-align: center; 12 | color:#E0E0E0; 13 | margin: 150px auto; 14 | text-shadow: 1px 2px rgba(0, 0, 0, 0.3); 15 | } 16 | 17 | .divider { 18 | margin: 50px auto; 19 | width: 250px; 20 | border-bottom: dashed #37474F 1px; 21 | } 22 | 23 | a { 24 | color: #2196F3; 25 | } 26 | 27 | h2 { 28 | display: block; 29 | margin: 75px auto; 30 | margin-bottom: 25px; 31 | width: 900px; 32 | font-family: 'Lato', sans-serif; 33 | font-weight: 100; 34 | font-size: 36px; 35 | color: #E0E0E0; 36 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 37 | } 38 | 39 | h3 { 40 | display: block; 41 | margin: 75px auto; 42 | margin-bottom: 25px; 43 | width: 880px; 44 | font-family: 'Lato', sans-serif; 45 | font-weight: 100; 46 | font-size: 30px; 47 | color: #E0E0E0; 48 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 49 | } 50 | 51 | .code, .output { 52 | width: 850px; 53 | margin: 25px auto; 54 | display: block; 55 | } 56 | 57 | .output { 58 | margin-top: -20px; 59 | } 60 | 61 | .output pre { 62 | background: #272822; 63 | color: #f8f8f2; 64 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 65 | padding: 1em; 66 | border-radius: 0.3em; 67 | font-size: 16px; 68 | } 69 | 70 | p { 71 | display: block; 72 | width: 800px; 73 | font-family: 'Open Sans', sans-serif; 74 | font-weight: 300; 75 | color: #FFF; 76 | margin: 25px auto; 77 | line-height: 1.25; 78 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 79 | } 80 | 81 | p b { 82 | display: inline-block; 83 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 84 | font-weight: 400; 85 | background-color: #37474F; 86 | padding: 1px 2px; 87 | border-radius: 4px; 88 | text-shadow: none; 89 | } 90 | 91 | 92 | .footer { 93 | font-family: 'Open Sans', sans-serif; 94 | font-weight: 300; 95 | color: #E0E0E0; 96 | font-size: 12px; 97 | text-align: center; 98 | margin-top: 50px; 99 | margin-bottom: 50px; 100 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 101 | } 102 | -------------------------------------------------------------------------------- /prism.css: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism-okaidia&languages=eiffel */ 2 | /** 3 | * okaidia theme for JavaScript, CSS and HTML 4 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 5 | * @author ocodia 6 | */ 7 | 8 | code[class*="language-"], 9 | pre[class*="language-"] { 10 | color: #f8f8f2; 11 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 12 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 13 | direction: ltr; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | word-wrap: normal; 19 | line-height: 1.5; 20 | 21 | -moz-tab-size: 4; 22 | -o-tab-size: 4; 23 | tab-size: 4; 24 | 25 | -webkit-hyphens: none; 26 | -moz-hyphens: none; 27 | -ms-hyphens: none; 28 | hyphens: none; 29 | } 30 | 31 | /* Code blocks */ 32 | pre[class*="language-"] { 33 | padding: 1em; 34 | margin: .5em 0; 35 | overflow: auto; 36 | border-radius: 0.3em; 37 | } 38 | 39 | :not(pre) > code[class*="language-"], 40 | pre[class*="language-"] { 41 | background: #272822; 42 | } 43 | 44 | /* Inline code */ 45 | :not(pre) > code[class*="language-"] { 46 | padding: .1em; 47 | border-radius: .3em; 48 | } 49 | 50 | .token.comment, 51 | .token.prolog, 52 | .token.doctype, 53 | .token.cdata { 54 | color: slategray; 55 | } 56 | 57 | .token.punctuation { 58 | color: #f8f8f2; 59 | } 60 | 61 | .namespace { 62 | opacity: .7; 63 | } 64 | 65 | .token.property, 66 | .token.tag, 67 | .token.constant, 68 | .token.symbol, 69 | .token.deleted { 70 | color: #f92672; 71 | } 72 | 73 | .token.boolean, 74 | .token.number { 75 | color: #ae81ff; 76 | } 77 | 78 | .token.selector, 79 | .token.attr-name, 80 | .token.string, 81 | .token.char, 82 | .token.builtin, 83 | .token.inserted { 84 | color: #a6e22e; 85 | } 86 | 87 | .token.operator, 88 | .token.entity, 89 | .token.url, 90 | .language-css .token.string, 91 | .style .token.string, 92 | .token.variable { 93 | color: #f8f8f2; 94 | } 95 | 96 | .token.atrule, 97 | .token.attr-value, 98 | .token.function { 99 | color: #e6db74; 100 | } 101 | 102 | .token.keyword { 103 | color: #66d9ef; 104 | } 105 | 106 | .token.regex, 107 | .token.important { 108 | color: #fd971f; 109 | } 110 | 111 | .token.important, 112 | .token.bold { 113 | font-weight: bold; 114 | } 115 | .token.italic { 116 | font-style: italic; 117 | } 118 | 119 | .token.entity { 120 | cursor: help; 121 | } 122 | -------------------------------------------------------------------------------- /prism.js: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism-okaidia&languages=eiffel */ 2 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=_self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(m instanceof r)){g.lastIndex=0;var y=g.exec(m);if(y){f&&(h=y[1].length);var v=y.index-1+h,y=y[0].slice(h),k=y.length,b=v+k,w=m.slice(0,v+1),P=m.slice(b+1),A=[d,1];w&&A.push(w);var N=new r(o,c?t.tokenize(y,c):y,p);A.push(N),P&&A.push(P),Array.prototype.splice.apply(l,A)}}}}}return l},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var l={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}t.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+""+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code,l=n.immediateClose;_self.postMessage(t.highlight(r,t.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 3 | Prism.languages.eiffel={string:[/"([^[]*)\[[\s\S]+?\]\1"/,/"([^{]*)\{[\s\S]+?\}\1"/,/"(?:%\s+%|%"|.)*?"/],comment:/--.*/,"char":/'(?:%'|.)+?'/,keyword:/\b(?:across|agent|alias|all|and|attached|as|assign|attribute|check|class|convert|create|Current|debug|deferred|detachable|do|else|elseif|end|ensure|expanded|export|external|feature|from|frozen|if|implies|inherit|inspect|invariant|like|local|loop|not|note|obsolete|old|once|or|Precursor|redefine|rename|require|rescue|Result|retry|select|separate|some|then|undefine|until|variant|Void|when|xor)\b/i,"boolean":/\b(?:True|False)\b/i,"class-name":{pattern:/\b[A-Z][\dA-Z_]*\b/g,alias:"builtin"},number:[/\b0[xcb][\da-f](?:_*[\da-f])*\b/i,/(?:\d(?:_*\d)*)?\.(?:(?:\d(?:_*\d)*)?[eE][+-]?)?\d(?:_*\d)*|\d(?:_*\d)*\.?/],punctuation:/:=|<<|>>|\(\||\|\)|->|\.(?=\w)|[{}[\];(),:?]/,operator:/\\\\|\|\.\.\||\.\.|\/[~\/=]?|[><]=?|[-+*^=~]/}; -------------------------------------------------------------------------------- /sidebar.css: -------------------------------------------------------------------------------- 1 | /* CSS for the sidebar */ 2 | 3 | #sidebar { 4 | position: fixed; 5 | display: table; 6 | top: 0; 7 | left: 0; 8 | padding-right: 40px; 9 | height: 100%; 10 | } 11 | 12 | #sidebar > div { 13 | background-color: rgba(38, 50, 56, 0); 14 | height: 100%; 15 | 16 | -webkit-transition: background-color 0.3s; 17 | transition: background-color 0.3s; 18 | -webkit-transition-timing-function: ease-in-out; 19 | transition-timing-function: ease-in-out; 20 | } 21 | 22 | #sidebar:hover > div { 23 | background-color: rgba(38, 50, 56, 1); 24 | } 25 | 26 | #sidebar a { 27 | display: block; 28 | width: 200px; 29 | font-family: 'Lato', sans-serif; 30 | font-weight: 400; 31 | font-size: 18px; 32 | color: #E0E0E0; 33 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 34 | text-decoration: none; 35 | padding: 6px 10px; 36 | padding-right: 15px; 37 | margin-left: -225px; 38 | 39 | -webkit-transition: margin-left 0.25s; 40 | transition: margin-left 0.25s; 41 | -webkit-transition-timing-function: ease-in-out; 42 | transition-timing-function: ease-in-out; 43 | } 44 | #sidebar:hover a { 45 | margin-left: 0px; 46 | } 47 | 48 | #sidebar a:first-child,#sidebar a.highlighted { 49 | border-right: solid 3px #66d9ef; 50 | background-color: rgba(255, 255, 255, 0.1); 51 | } 52 | #sidebar a:hover { 53 | background-color: rgba(255, 255, 255, 0.05); 54 | } -------------------------------------------------------------------------------- /sidebar.js: -------------------------------------------------------------------------------- 1 | angular.module('sidebar', []) 2 | .controller('SidebarController', ["$window", "$scope", function($window, $scope){ 3 | this.scrollTo = function (index) { 4 | $window.scrollTo(0, document.getElementsByTagName("h2").item(index).offsetTop - 25); 5 | }; 6 | angular.element($window).on('scroll', function(){ 7 | 8 | var i = 0, 9 | h2 = document.getElementsByTagName("h2"); 10 | 11 | while (i < h2.length) { 12 | if (h2.item(i).offsetTop >= $window.scrollY + 75) 13 | break; 14 | i++; 15 | } 16 | 17 | $scope.sidebarCtrl.highlighted = i - 1; 18 | $scope.$apply(); 19 | 20 | }); 21 | }]) 22 | .directive('sidebar', function() { 23 | return { 24 | restrict : 'E', 25 | template: function(elem, attr){ 26 | 27 | var html = " "; 35 | 36 | return html; 37 | 38 | } 39 | }; 40 | }); --------------------------------------------------------------------------------