fancy 0.3.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/AUTHORS +7 -0
- data/LICENSE +19 -0
- data/README +173 -0
- data/Rakefile +255 -0
- data/bin/fancy +40 -0
- data/bin/fdoc +23 -0
- data/bin/fyi +22 -0
- data/bin/ifancy +46 -0
- data/boot/README +12 -0
- data/boot/code_loader.rb +165 -0
- data/boot/compile.fy +3 -0
- data/boot/fancy_ext.rb +13 -0
- data/boot/fancy_ext/block_env.rb +29 -0
- data/boot/fancy_ext/class.rb +26 -0
- data/boot/fancy_ext/kernel.rb +12 -0
- data/boot/fancy_ext/module.rb +89 -0
- data/boot/fancy_ext/object.rb +34 -0
- data/boot/fancy_ext/string_helper.rb +10 -0
- data/boot/load.rb +72 -0
- data/boot/rbx-compiler/README +12 -0
- data/boot/rbx-compiler/compiler.rb +24 -0
- data/boot/rbx-compiler/compiler/ast.rb +23 -0
- data/boot/rbx-compiler/compiler/ast/README +11 -0
- data/boot/rbx-compiler/compiler/ast/array_literal.rb +13 -0
- data/boot/rbx-compiler/compiler/ast/assign.rb +57 -0
- data/boot/rbx-compiler/compiler/ast/block.rb +70 -0
- data/boot/rbx-compiler/compiler/ast/class_def.rb +35 -0
- data/boot/rbx-compiler/compiler/ast/expression_list.rb +57 -0
- data/boot/rbx-compiler/compiler/ast/hash_literal.rb +11 -0
- data/boot/rbx-compiler/compiler/ast/identifier.rb +120 -0
- data/boot/rbx-compiler/compiler/ast/match.rb +81 -0
- data/boot/rbx-compiler/compiler/ast/message_send.rb +71 -0
- data/boot/rbx-compiler/compiler/ast/method_def.rb +116 -0
- data/boot/rbx-compiler/compiler/ast/node.rb +6 -0
- data/boot/rbx-compiler/compiler/ast/range_literal.rb +22 -0
- data/boot/rbx-compiler/compiler/ast/require.rb +20 -0
- data/boot/rbx-compiler/compiler/ast/return.rb +29 -0
- data/boot/rbx-compiler/compiler/ast/ruby_args.rb +35 -0
- data/boot/rbx-compiler/compiler/ast/script.rb +56 -0
- data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +39 -0
- data/boot/rbx-compiler/compiler/ast/string_literal.rb +14 -0
- data/boot/rbx-compiler/compiler/ast/super.rb +25 -0
- data/boot/rbx-compiler/compiler/ast/try_catch_block.rb +220 -0
- data/boot/rbx-compiler/compiler/ast/tuple_literal.rb +33 -0
- data/boot/rbx-compiler/compiler/command.rb +39 -0
- data/boot/rbx-compiler/compiler/compiler.rb +83 -0
- data/boot/rbx-compiler/compiler/stages.rb +99 -0
- data/boot/rbx-compiler/parser.rb +2 -0
- data/boot/rbx-compiler/parser/README +15 -0
- data/boot/rbx-compiler/parser/Rakefile +54 -0
- data/boot/rbx-compiler/parser/extconf.rb +3 -0
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/fancy_parser.c +46 -0
- data/boot/rbx-compiler/parser/fancy_parser.h +8 -0
- data/boot/rbx-compiler/parser/lexer.lex +180 -0
- data/boot/rbx-compiler/parser/parser.rb +356 -0
- data/boot/rbx-compiler/parser/parser.y +711 -0
- data/boot/rsexp_pretty_printer.rb +76 -0
- data/doc/api/fancy.css +93 -0
- data/doc/api/fancy.jsonp +1 -0
- data/doc/api/fdoc.js +187 -0
- data/doc/api/index.html +57 -0
- data/doc/api/underscore-min.js +18 -0
- data/doc/features.md +228 -0
- data/examples/argv.fy +8 -0
- data/examples/arithmetic.fy +7 -0
- data/examples/armstrong_numbers.fy +33 -0
- data/examples/array.fy +52 -0
- data/examples/blocks.fy +15 -0
- data/examples/boolean.fy +24 -0
- data/examples/call_with_receiver.fy +9 -0
- data/examples/class.fy +68 -0
- data/examples/closures.fy +24 -0
- data/examples/constant_access.fy +15 -0
- data/examples/default_args.fy +17 -0
- data/examples/define_methods.fy +15 -0
- data/examples/documentation.fy +57 -0
- data/examples/documentation_formatters.fy +25 -0
- data/examples/echo.fy +16 -0
- data/examples/empty_catch.fy +4 -0
- data/examples/exception.fy +9 -0
- data/examples/factorial.fy +12 -0
- data/examples/fibonacci.fy +16 -0
- data/examples/files.fy +23 -0
- data/examples/finally.fy +5 -0
- data/examples/game_of_life.fy +148 -0
- data/examples/hashes.fy +7 -0
- data/examples/hello_world.fy +6 -0
- data/examples/html_generator.fy +54 -0
- data/examples/implicit_return.fy +3 -0
- data/examples/matchers.fy +6 -0
- data/examples/methods.fy +29 -0
- data/examples/nested_classes.fy +27 -0
- data/examples/nested_try.fy +9 -0
- data/examples/numbers.fy +12 -0
- data/examples/pattern_matching.fy +40 -0
- data/examples/person.fy +65 -0
- data/examples/project-euler/01.fy +8 -0
- data/examples/project-euler/02.fy +21 -0
- data/examples/project-euler/28.fy +33 -0
- data/examples/rbx/and_or.fy +7 -0
- data/examples/rbx/blocks.fy +22 -0
- data/examples/rbx/classes.fy +32 -0
- data/examples/rbx/hello.fy +8 -0
- data/examples/rbx/include.fy +12 -0
- data/examples/rbx/inherit.fy +11 -0
- data/examples/rbx/methods.fy +15 -0
- data/examples/rbx/nested_classes.fy +9 -0
- data/examples/rbx/require.fy +3 -0
- data/examples/rbx/strings.fy +5 -0
- data/examples/regex.fy +7 -0
- data/examples/require.fy +7 -0
- data/examples/retry.fy +12 -0
- data/examples/return.fy +13 -0
- data/examples/ruby_require.fy +7 -0
- data/examples/ruby_send.fy +3 -0
- data/examples/singleton_methods.fy +21 -0
- data/examples/stupid_quicksort.fy +12 -0
- data/examples/threads.fy +18 -0
- data/examples/tuple.fy +8 -0
- data/examples/webserver/webserver.fy +18 -0
- data/lib/argv.fy +36 -0
- data/lib/array.fy +207 -0
- data/lib/block.fy +88 -0
- data/lib/boot.fy +41 -0
- data/lib/class.fy +106 -0
- data/lib/compiler.fy +14 -0
- data/lib/compiler/ast.fy +40 -0
- data/lib/compiler/ast/assign.fy +96 -0
- data/lib/compiler/ast/block.fy +84 -0
- data/lib/compiler/ast/class_def.fy +33 -0
- data/lib/compiler/ast/expression_list.fy +47 -0
- data/lib/compiler/ast/identifier.fy +113 -0
- data/lib/compiler/ast/literals.fy +122 -0
- data/lib/compiler/ast/match.fy +88 -0
- data/lib/compiler/ast/message_send.fy +110 -0
- data/lib/compiler/ast/method_def.fy +90 -0
- data/lib/compiler/ast/node.fy +7 -0
- data/lib/compiler/ast/range.fy +16 -0
- data/lib/compiler/ast/require.fy +15 -0
- data/lib/compiler/ast/return.fy +23 -0
- data/lib/compiler/ast/script.fy +52 -0
- data/lib/compiler/ast/singleton_method_def.fy +35 -0
- data/lib/compiler/ast/super.fy +17 -0
- data/lib/compiler/ast/try_catch.fy +176 -0
- data/lib/compiler/ast/tuple_literal.fy +34 -0
- data/lib/compiler/command.fy +51 -0
- data/lib/compiler/compiler.fy +73 -0
- data/lib/compiler/stages.fy +81 -0
- data/lib/directory.fy +17 -0
- data/lib/documentation.fy +115 -0
- data/lib/enumerable.fy +269 -0
- data/lib/eval.fy +31 -0
- data/lib/fancy_spec.fy +202 -0
- data/lib/fdoc.fy +359 -0
- data/lib/fdoc_hook.fy +10 -0
- data/lib/file.fy +54 -0
- data/lib/hash.fy +56 -0
- data/lib/main.fy +80 -0
- data/lib/method.fy +22 -0
- data/lib/nil_class.fy +56 -0
- data/lib/number.fy +87 -0
- data/lib/object.fy +170 -0
- data/lib/package.fy +61 -0
- data/lib/package/dependency.fy +24 -0
- data/lib/package/installer.fy +180 -0
- data/lib/package/specification.fy +55 -0
- data/lib/package/uninstaller.fy +15 -0
- data/lib/parser.fy +4 -0
- data/lib/parser/ext/README +15 -0
- data/lib/parser/ext/ext.c +42 -0
- data/lib/parser/ext/ext.h +8 -0
- data/lib/parser/ext/extconf.rb +3 -0
- data/lib/parser/ext/lexer.lex +187 -0
- data/lib/parser/ext/parser.y +744 -0
- data/lib/parser/methods.fy +297 -0
- data/lib/rbx.fy +37 -0
- data/lib/rbx/array.fy +237 -0
- data/lib/rbx/bignum.fy +23 -0
- data/lib/rbx/block.fy +9 -0
- data/lib/rbx/class.fy +129 -0
- data/lib/rbx/code_loader.fy +192 -0
- data/lib/rbx/console.fy +63 -0
- data/lib/rbx/directory.fy +46 -0
- data/lib/rbx/documentation.fy +64 -0
- data/lib/rbx/environment_variables.fy +3 -0
- data/lib/rbx/exception.fy +30 -0
- data/lib/rbx/false_class.fy +58 -0
- data/lib/rbx/fiber.fy +25 -0
- data/lib/rbx/file.fy +191 -0
- data/lib/rbx/fixnum.fy +25 -0
- data/lib/rbx/float.fy +14 -0
- data/lib/rbx/hash.fy +38 -0
- data/lib/rbx/integer.fy +15 -0
- data/lib/rbx/io.fy +30 -0
- data/lib/rbx/match_data.fy +9 -0
- data/lib/rbx/method.fy +22 -0
- data/lib/rbx/name_error.fy +3 -0
- data/lib/rbx/no_method_error.fy +15 -0
- data/lib/rbx/object.fy +117 -0
- data/lib/rbx/range.fy +15 -0
- data/lib/rbx/regexp.fy +9 -0
- data/lib/rbx/string.fy +63 -0
- data/lib/rbx/symbol.fy +12 -0
- data/lib/rbx/system.fy +37 -0
- data/lib/rbx/tcp_server.fy +6 -0
- data/lib/rbx/tcp_socket.fy +7 -0
- data/lib/rbx/thread.fy +75 -0
- data/lib/rbx/tuple.fy +37 -0
- data/lib/set.fy +61 -0
- data/lib/stack.fy +51 -0
- data/lib/string.fy +58 -0
- data/lib/struct.fy +13 -0
- data/lib/symbol.fy +23 -0
- data/lib/true_class.fy +43 -0
- data/lib/tuple.fy +68 -0
- data/lib/version.fy +6 -0
- data/tests/argv.fy +13 -0
- data/tests/array.fy +343 -0
- data/tests/assignment.fy +53 -0
- data/tests/block.fy +103 -0
- data/tests/class.fy +409 -0
- data/tests/control_flow.fy +79 -0
- data/tests/documentation.fy +24 -0
- data/tests/exception.fy +115 -0
- data/tests/file.fy +86 -0
- data/tests/hash.fy +101 -0
- data/tests/method.fy +131 -0
- data/tests/nil_class.fy +55 -0
- data/tests/number.fy +128 -0
- data/tests/object.fy +125 -0
- data/tests/parsing/sexp.fy +50 -0
- data/tests/pattern_matching.fy +82 -0
- data/tests/range.fy +11 -0
- data/tests/set.fy +10 -0
- data/tests/stack.fy +22 -0
- data/tests/string.fy +102 -0
- data/tests/symbol.fy +17 -0
- data/tests/true_class.fy +63 -0
- data/tests/tuple.fy +21 -0
- data/tools/fancy-mode.el +63 -0
- metadata +321 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require("fileutils")
|
2
|
+
|
3
|
+
class Fancy {
|
4
|
+
class Compiler Command {
|
5
|
+
|
6
|
+
def self option: argv flag: name {
|
7
|
+
argv delete(name)
|
8
|
+
}
|
9
|
+
|
10
|
+
def self option: argv value: name {
|
11
|
+
idx = argv index(name)
|
12
|
+
if: idx then: {
|
13
|
+
value = argv delete_at(idx + 1)
|
14
|
+
argv delete_at(idx)
|
15
|
+
value
|
16
|
+
} else: {
|
17
|
+
nil
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
def self run: argv {
|
22
|
+
batch = option: argv flag: "--batch"
|
23
|
+
print = option: argv flag: "-B"
|
24
|
+
src_path = option: argv value: "--source-path"
|
25
|
+
out_path = option: argv value: "--output-path"
|
26
|
+
argv each() |f| {
|
27
|
+
o = nil
|
28
|
+
if: (out_path && src_path) then: {
|
29
|
+
o = f sub(src_path, out_path) + "c"
|
30
|
+
}
|
31
|
+
compile: f to: o info: batch print: print
|
32
|
+
}
|
33
|
+
if: batch then: {
|
34
|
+
size = argv size()
|
35
|
+
files = "file"
|
36
|
+
{ files = files + "s" } if: (size > 1)
|
37
|
+
"Compiled " ++ (argv size()) ++ " " ++ files ++ "." . println
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
def self compile: file to: to (nil) info: info (false) print: print (false) {
|
42
|
+
if: info then: {
|
43
|
+
"Compiling " ++ file println
|
44
|
+
}
|
45
|
+
if: to then: {
|
46
|
+
FileUtils mkdir_p(File dirname(to))
|
47
|
+
}
|
48
|
+
Compiler compile_file: file to: to line: 1 print: print
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Fancy {
|
2
|
+
|
3
|
+
class Compiler : Rubinius Compiler {
|
4
|
+
|
5
|
+
read_write_slots: ['parser, 'generator, 'packager, 'writer]
|
6
|
+
|
7
|
+
def self compiled_name: file {
|
8
|
+
"""
|
9
|
+
Returns a the compiled filename for @file
|
10
|
+
|
11
|
+
If file ends with .fy extention the will return with .fyc extension
|
12
|
+
Otherwise it will append .compiled.fyc to the filename.
|
13
|
+
"""
|
14
|
+
|
15
|
+
if: (file suffix?(".fy")) then: {
|
16
|
+
file + "c"
|
17
|
+
} else: {
|
18
|
+
file + ".compiled.fyc"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
def self from: first_stage to: last_stage {
|
23
|
+
"Creates a new compiler from @first_stage to @last_stage"
|
24
|
+
|
25
|
+
new(first_stage, last_stage)
|
26
|
+
}
|
27
|
+
|
28
|
+
def self compile_code: code vars: scope file: file line: line print: print (false) {
|
29
|
+
compiler = from: 'fancy_code to: 'compiled_method
|
30
|
+
parser = compiler parser
|
31
|
+
parser root: Rubinius AST EvalExpression
|
32
|
+
parser input: code file: file line: line
|
33
|
+
if: print then: {
|
34
|
+
parser print: true
|
35
|
+
printer = compiler packager print()
|
36
|
+
printer bytecode=(true)
|
37
|
+
}
|
38
|
+
compiler generator variable_scope: scope
|
39
|
+
result = nil
|
40
|
+
try {
|
41
|
+
result = compiler run()
|
42
|
+
} catch Exception => e {
|
43
|
+
compiler_error("Error trying to compile " ++ file, e)
|
44
|
+
}
|
45
|
+
result
|
46
|
+
}
|
47
|
+
|
48
|
+
def self compile_file: file to: output (nil) line: line (1) print: print (false) {
|
49
|
+
compiler = from: 'fancy_file to: 'compiled_file
|
50
|
+
parser = compiler parser
|
51
|
+
parser root: Rubinius AST Script
|
52
|
+
parser input: file line: line
|
53
|
+
if: print then: {
|
54
|
+
parser print: true
|
55
|
+
printer = compiler packager print()
|
56
|
+
printer bytecode=(true)
|
57
|
+
}
|
58
|
+
writer = compiler writer
|
59
|
+
if: output then: {
|
60
|
+
writer name=(output)
|
61
|
+
} else: {
|
62
|
+
writer name=(compiled_name: file)
|
63
|
+
}
|
64
|
+
try {
|
65
|
+
compiler run()
|
66
|
+
} catch Exception => e {
|
67
|
+
compiler_error("Error trying to compile " ++ file, e)
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
}
|
72
|
+
|
73
|
+
}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class Fancy Compiler Stages {
|
2
|
+
|
3
|
+
class Stage : Rubinius Compiler Stage {
|
4
|
+
|
5
|
+
initialize = |compiler, last| {
|
6
|
+
sup = Rubinius Compiler Stage instance_method('initialize)
|
7
|
+
sup bind(self) call(compiler, last)
|
8
|
+
initialize: compiler last: last
|
9
|
+
}
|
10
|
+
define_method('initialize, &initialize)
|
11
|
+
|
12
|
+
def self stage: name next: next (nil) {
|
13
|
+
stage(name)
|
14
|
+
next_stage(next)
|
15
|
+
}
|
16
|
+
|
17
|
+
run = { self run; run_next() }
|
18
|
+
define_method('run, &run)
|
19
|
+
|
20
|
+
}
|
21
|
+
|
22
|
+
class FancyGenerator : Stage {
|
23
|
+
|
24
|
+
stage: 'fancy_bytecode next: Rubinius Compiler Encoder
|
25
|
+
|
26
|
+
read_write_slots: ['variable_scope]
|
27
|
+
|
28
|
+
def initialize: compiler last: last {
|
29
|
+
@variable_scope = nil
|
30
|
+
compiler generator: self
|
31
|
+
}
|
32
|
+
|
33
|
+
def run {
|
34
|
+
@output = Rubinius Generator new()
|
35
|
+
@input variable_scope=(@variable_scope)
|
36
|
+
@input bytecode(@output)
|
37
|
+
@output close()
|
38
|
+
}
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
class FancyCodeParser : Stage {
|
43
|
+
stage: 'fancy_code next: FancyGenerator
|
44
|
+
read_write_slots: ['root, 'print]
|
45
|
+
|
46
|
+
def initialize: compiler last: last {
|
47
|
+
compiler parser: self
|
48
|
+
}
|
49
|
+
|
50
|
+
def input: @code file: @filename line: @line (1) {}
|
51
|
+
|
52
|
+
def run {
|
53
|
+
ast = Fancy Parser parse_code: @code file: @filename line: @line
|
54
|
+
# if: @print then: { ast inspect println }
|
55
|
+
@output = @root new(ast)
|
56
|
+
@output file=(@filename)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
class FancyFileParser : Stage {
|
61
|
+
|
62
|
+
stage: 'fancy_file next: FancyGenerator
|
63
|
+
read_write_slots: ['root, 'print]
|
64
|
+
|
65
|
+
def initialize: compiler last: last {
|
66
|
+
compiler parser: self
|
67
|
+
}
|
68
|
+
|
69
|
+
def input: @filename line: @line (1) {}
|
70
|
+
|
71
|
+
def run {
|
72
|
+
ast = Fancy Parser parse_file: @filename line: @line
|
73
|
+
# if: @print then: { ast inspect println }
|
74
|
+
@output = @root new(ast)
|
75
|
+
@output file=(@filename)
|
76
|
+
}
|
77
|
+
|
78
|
+
}
|
79
|
+
|
80
|
+
}
|
81
|
+
|
data/lib/directory.fy
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Directory {
|
2
|
+
"""
|
3
|
+
Instances of @Directory@ represent directories in the filesystem of
|
4
|
+
the operating system, in which Fancy is being run.
|
5
|
+
"""
|
6
|
+
|
7
|
+
def self exists?: dirname {
|
8
|
+
"""
|
9
|
+
@dirname Path of @Directory@ to check for existance.
|
10
|
+
@@return @true, if @Directory@ exists, @false otherwise.
|
11
|
+
|
12
|
+
Indicates, if a Directory exists with a given pathname.
|
13
|
+
"""
|
14
|
+
|
15
|
+
(File exists?: dirname) and: (File directory?: dirname)
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,115 @@
|
|
1
|
+
class Fancy Documentation {
|
2
|
+
|
3
|
+
"""
|
4
|
+
A Fancy Documentation object is a holder for docstrings and specs.
|
5
|
+
Keeps a registry of documentation for anything Fancy.
|
6
|
+
|
7
|
+
Provides methods for searching and formatting objects' docstrings
|
8
|
+
this can be be handy for users of interactive Fancy REPL,
|
9
|
+
document generators, instrospection toos, IDEs, anything!.
|
10
|
+
|
11
|
+
This object can be converted to just anything by using its format:
|
12
|
+
method. formatters can be registered with Fancy Documentation formatter:is:
|
13
|
+
|
14
|
+
By default two formatters are defined:
|
15
|
+
|
16
|
+
'fancy => Returns the Fancy::Documentation object
|
17
|
+
'string => Returns the docs string representation
|
18
|
+
"""
|
19
|
+
read_write_slots: ['object, 'docs, 'specs]
|
20
|
+
|
21
|
+
instance_method: 'docs . executable() . documentation: """
|
22
|
+
An array of docstrings for the object beind documented.
|
23
|
+
|
24
|
+
We have an array of docstrings because in Fancy, some
|
25
|
+
things like classes can be re-openned and the user may
|
26
|
+
specify new documentation for it each time. Thus we dont
|
27
|
+
want to loose the previous documentation but rather build
|
28
|
+
upon it. That is, fancy supports incremental documentation.
|
29
|
+
"""
|
30
|
+
|
31
|
+
instance_method: 'specs . documentation: """
|
32
|
+
An array of associated Fancy specs for the object
|
33
|
+
being documented.
|
34
|
+
|
35
|
+
Its a lot better to keep the associated specs in
|
36
|
+
Fancy Documentation objects instead of just having them
|
37
|
+
in method instances. This allows us to associate any object
|
38
|
+
with an spec example.
|
39
|
+
|
40
|
+
This way you can have a single Fancy spec example that
|
41
|
+
is related to many objects (methods, constants, classes)
|
42
|
+
that are being specified. Later in documentation, we can
|
43
|
+
provide links to all specs where an object is being exercised.
|
44
|
+
"""
|
45
|
+
|
46
|
+
def to_s { @docs join: "\n" }
|
47
|
+
|
48
|
+
def format: format {
|
49
|
+
"""
|
50
|
+
If format is specified, the documentation string will be
|
51
|
+
converted using the corresponding formatter. This allows
|
52
|
+
you to extend Fancy documentation system, and produce
|
53
|
+
html documents, man pages, or anything you can imagine.
|
54
|
+
"""
|
55
|
+
formatter = Fancy Documentation formatter: format
|
56
|
+
{ "No such documentation format: " ++ format . raise! } unless: formatter
|
57
|
+
formatter call: [self]
|
58
|
+
}
|
59
|
+
|
60
|
+
def self for: obj append: docstring {
|
61
|
+
"""
|
62
|
+
Append docstring to the documentation for obj.
|
63
|
+
If obj has no documentation, one is created for it.
|
64
|
+
"""
|
65
|
+
doc = self for: obj
|
66
|
+
doc if_do: {
|
67
|
+
doc docs << docstring
|
68
|
+
} else: {
|
69
|
+
doc = self for: obj is: docstring
|
70
|
+
}
|
71
|
+
doc
|
72
|
+
}
|
73
|
+
|
74
|
+
def self formatter: name {
|
75
|
+
"Obtain a formatter by the given name. Returns a callable object"
|
76
|
+
self formatters at: name
|
77
|
+
}
|
78
|
+
|
79
|
+
def self formatter: name is: callable {
|
80
|
+
"Register a callable object as formatter under name."
|
81
|
+
self formatters at: name put: callable
|
82
|
+
}
|
83
|
+
|
84
|
+
def self formatters {
|
85
|
+
"Obtain the hash of known documentation formatters."
|
86
|
+
unless: @formatters do: { @formatters = <[]> }
|
87
|
+
@formatters
|
88
|
+
}
|
89
|
+
|
90
|
+
self formatter: 'fancy is: |doc| { doc }
|
91
|
+
self formatter: 'string is: |doc| { doc to_s }
|
92
|
+
|
93
|
+
# TODO: implement. Plain is just like string but including spec names.
|
94
|
+
self formatter: 'plain is: |doc| { doc to_s }
|
95
|
+
|
96
|
+
}
|
97
|
+
|
98
|
+
class Fancy Documentation RDiscount {
|
99
|
+
|
100
|
+
"A documentation formatter using ruby's RDiscount markdown"
|
101
|
+
Fancy Documentation formatter: 'rdiscount is: |d| { rdiscount: d }
|
102
|
+
|
103
|
+
# Register as default markdown formatter.
|
104
|
+
Fancy Documentation formatter: 'markdown is: |d| { rdiscount: d }
|
105
|
+
|
106
|
+
def self rdiscount: doc {
|
107
|
+
"Format string as HTML using RDiscount ruby gem."
|
108
|
+
require("rubygems")
|
109
|
+
require("rdiscount")
|
110
|
+
RDiscount.new(doc to_s).to_html()
|
111
|
+
}
|
112
|
+
|
113
|
+
}
|
114
|
+
|
115
|
+
|
data/lib/enumerable.fy
ADDED
@@ -0,0 +1,269 @@
|
|
1
|
+
class FancyEnumerable {
|
2
|
+
"""
|
3
|
+
Mixin-Class with useful methods for collections that implement an @each:@ method.
|
4
|
+
"""
|
5
|
+
|
6
|
+
def includes?: item {
|
7
|
+
"""
|
8
|
+
@item Item to check if it's included in @self.
|
9
|
+
@return @true, if @item in @self, otherwise @false.
|
10
|
+
|
11
|
+
Indicates, if a collection includes a given element.
|
12
|
+
"""
|
13
|
+
any?: |x| { item == x }
|
14
|
+
}
|
15
|
+
|
16
|
+
def each: each_block in_between: between_block {
|
17
|
+
"""
|
18
|
+
Similar to @each:@ but calls an additional @Block@ between
|
19
|
+
calling the first @Block@ for each element in self.
|
20
|
+
"""
|
21
|
+
|
22
|
+
count = 0
|
23
|
+
size = self size
|
24
|
+
each: |x| {
|
25
|
+
each_block call: [x]
|
26
|
+
unless: (count == (size - 1)) do: {
|
27
|
+
between_block call
|
28
|
+
}
|
29
|
+
count = count + 1
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
def any?: condition {
|
34
|
+
"""
|
35
|
+
@condition @Block@ (or @Callable) that is used to check if any element in @self yields true for it.
|
36
|
+
@return @true, if @condition yields @true for any element, @false otherwise.
|
37
|
+
|
38
|
+
Indicates, if any element meets the condition.
|
39
|
+
"""
|
40
|
+
|
41
|
+
each: |x| {
|
42
|
+
if: (condition call: [x]) then: {
|
43
|
+
return true
|
44
|
+
}
|
45
|
+
}
|
46
|
+
nil
|
47
|
+
}
|
48
|
+
|
49
|
+
def all?: condition {
|
50
|
+
"""
|
51
|
+
Similar to @FancyEnumerable#any?:@ just checking for all elements.
|
52
|
+
Indicates, if all elements meet the condition.
|
53
|
+
"""
|
54
|
+
|
55
|
+
each: |x| {
|
56
|
+
unless: (condition call: [x]) do: {
|
57
|
+
return false
|
58
|
+
}
|
59
|
+
}
|
60
|
+
true
|
61
|
+
}
|
62
|
+
|
63
|
+
def find: item {
|
64
|
+
"Returns @nil, if the given object isn't found, or the object, if it is found."
|
65
|
+
|
66
|
+
if: (item is_a?: Block) then: {
|
67
|
+
find_by: item
|
68
|
+
} else: {
|
69
|
+
each: |x| {
|
70
|
+
if: (item == x) then: {
|
71
|
+
return x
|
72
|
+
}
|
73
|
+
}
|
74
|
+
nil
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
def find_by: block {
|
79
|
+
"""
|
80
|
+
Similar to @find:@ but takes a block that is called for each element to find it.
|
81
|
+
"""
|
82
|
+
|
83
|
+
each: |x| {
|
84
|
+
block call: [x] . if_do: |item| {
|
85
|
+
return item
|
86
|
+
}
|
87
|
+
}
|
88
|
+
nil
|
89
|
+
}
|
90
|
+
|
91
|
+
def map: block {
|
92
|
+
"Returns a new @Array@ with the results of calling a given block for every element"
|
93
|
+
|
94
|
+
coll = []
|
95
|
+
each: |x| {
|
96
|
+
coll << (block call: [x])
|
97
|
+
}
|
98
|
+
coll
|
99
|
+
}
|
100
|
+
|
101
|
+
def select: condition {
|
102
|
+
"Returns a new @Array@ with all elements that meet the given condition block."
|
103
|
+
|
104
|
+
coll = []
|
105
|
+
each: |x| {
|
106
|
+
{ coll << x } if: $ condition call: [x]
|
107
|
+
}
|
108
|
+
coll
|
109
|
+
}
|
110
|
+
|
111
|
+
def reject: condition {
|
112
|
+
"Returns a new @Array@ with all elements that don't meet the given condition block."
|
113
|
+
|
114
|
+
coll = []
|
115
|
+
each: |x| {
|
116
|
+
{ coll << x } unless: $ condition call: [x]
|
117
|
+
}
|
118
|
+
coll
|
119
|
+
}
|
120
|
+
|
121
|
+
def take_while: condition {
|
122
|
+
"Returns a new @Array@ by taking elements from the beginning as long as they meet the given condition block."
|
123
|
+
coll = []
|
124
|
+
each: |x| {
|
125
|
+
if: (condition call: [x]) then: {
|
126
|
+
coll << x
|
127
|
+
} else: {
|
128
|
+
return coll
|
129
|
+
}
|
130
|
+
}
|
131
|
+
coll
|
132
|
+
}
|
133
|
+
|
134
|
+
def drop_while: condition {
|
135
|
+
"Returns a new @Array@ by skipping elements from the beginning as long as they meet the given condition block."
|
136
|
+
|
137
|
+
coll = []
|
138
|
+
drop = nil
|
139
|
+
first_check = true
|
140
|
+
each: |x| {
|
141
|
+
if: (drop or: first_check) then: {
|
142
|
+
drop = condition call: [x]
|
143
|
+
first_check = nil
|
144
|
+
# check, if we actually have to insert his one:
|
145
|
+
unless: drop do: {
|
146
|
+
coll << x
|
147
|
+
}
|
148
|
+
} else: {
|
149
|
+
coll << x
|
150
|
+
}
|
151
|
+
}
|
152
|
+
coll
|
153
|
+
}
|
154
|
+
|
155
|
+
def take: amount {
|
156
|
+
i = 0
|
157
|
+
self take_while: {
|
158
|
+
i = i + 1
|
159
|
+
i <= amount
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
def drop: amount {
|
164
|
+
i = 0
|
165
|
+
self drop_while: {
|
166
|
+
i = i + 1
|
167
|
+
i <= amount
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
def reduce: block init_val: init_val {
|
172
|
+
"Calculates a value based on a given block to be called on an accumulator value and an initial value."
|
173
|
+
|
174
|
+
acc = init_val
|
175
|
+
each: |x| {
|
176
|
+
acc = (block call: [acc, x])
|
177
|
+
}
|
178
|
+
acc
|
179
|
+
}
|
180
|
+
|
181
|
+
def uniq {
|
182
|
+
"Returns a new Array with all unique values (double entries are skipped)."
|
183
|
+
|
184
|
+
uniq_vals = []
|
185
|
+
each: |x| {
|
186
|
+
unless: (uniq_vals includes?: x) do: {
|
187
|
+
uniq_vals << x
|
188
|
+
}
|
189
|
+
}
|
190
|
+
uniq_vals
|
191
|
+
}
|
192
|
+
|
193
|
+
def size {
|
194
|
+
"Returns the size of an Enumerable."
|
195
|
+
|
196
|
+
i = 0
|
197
|
+
each: |x| {
|
198
|
+
i = i + 1
|
199
|
+
}
|
200
|
+
i
|
201
|
+
}
|
202
|
+
|
203
|
+
def empty? {
|
204
|
+
"Indicates, if the Enumerable is empty (has no elements)."
|
205
|
+
self size == 0
|
206
|
+
}
|
207
|
+
|
208
|
+
def first {
|
209
|
+
self each: |x| {
|
210
|
+
return x
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
def last {
|
215
|
+
"Returns the last element in an Enumerable."
|
216
|
+
|
217
|
+
item = nil
|
218
|
+
each: |x| {
|
219
|
+
item = x
|
220
|
+
}
|
221
|
+
item
|
222
|
+
}
|
223
|
+
|
224
|
+
def compact {
|
225
|
+
"Returns a new @Array@ with all values removed that are @nil ( return @true on @nil? )."
|
226
|
+
|
227
|
+
reject: |x| { x nil? }
|
228
|
+
}
|
229
|
+
|
230
|
+
def superior_by: comparison_block {
|
231
|
+
"Returns the superiour element in the @Enumerable that has met the given comparison block with all other elements."
|
232
|
+
|
233
|
+
retval = self first
|
234
|
+
each: |x| {
|
235
|
+
if: (comparison_block call: [x, retval]) then: {
|
236
|
+
retval = x
|
237
|
+
}
|
238
|
+
}
|
239
|
+
retval
|
240
|
+
}
|
241
|
+
|
242
|
+
def max {
|
243
|
+
"Returns the maximum value in the Enumerable (via the '>' comparison message)."
|
244
|
+
superior_by: '>
|
245
|
+
}
|
246
|
+
|
247
|
+
def min {
|
248
|
+
"Returns the minimum value in the Enumerable (via the '<' comparison message)."
|
249
|
+
superior_by: '<
|
250
|
+
}
|
251
|
+
|
252
|
+
def partition_by: block {
|
253
|
+
last = block call: [self first]
|
254
|
+
coll = []
|
255
|
+
tmp_coll = []
|
256
|
+
self each: |x| {
|
257
|
+
tmp = block call: [x]
|
258
|
+
if: (tmp != last) then: {
|
259
|
+
coll << tmp_coll
|
260
|
+
tmp_coll = [x]
|
261
|
+
} else: {
|
262
|
+
tmp_coll << x
|
263
|
+
}
|
264
|
+
last = tmp
|
265
|
+
}
|
266
|
+
coll << tmp_coll
|
267
|
+
coll
|
268
|
+
}
|
269
|
+
}
|