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.
Files changed (242) hide show
  1. data/AUTHORS +7 -0
  2. data/LICENSE +19 -0
  3. data/README +173 -0
  4. data/Rakefile +255 -0
  5. data/bin/fancy +40 -0
  6. data/bin/fdoc +23 -0
  7. data/bin/fyi +22 -0
  8. data/bin/ifancy +46 -0
  9. data/boot/README +12 -0
  10. data/boot/code_loader.rb +165 -0
  11. data/boot/compile.fy +3 -0
  12. data/boot/fancy_ext.rb +13 -0
  13. data/boot/fancy_ext/block_env.rb +29 -0
  14. data/boot/fancy_ext/class.rb +26 -0
  15. data/boot/fancy_ext/kernel.rb +12 -0
  16. data/boot/fancy_ext/module.rb +89 -0
  17. data/boot/fancy_ext/object.rb +34 -0
  18. data/boot/fancy_ext/string_helper.rb +10 -0
  19. data/boot/load.rb +72 -0
  20. data/boot/rbx-compiler/README +12 -0
  21. data/boot/rbx-compiler/compiler.rb +24 -0
  22. data/boot/rbx-compiler/compiler/ast.rb +23 -0
  23. data/boot/rbx-compiler/compiler/ast/README +11 -0
  24. data/boot/rbx-compiler/compiler/ast/array_literal.rb +13 -0
  25. data/boot/rbx-compiler/compiler/ast/assign.rb +57 -0
  26. data/boot/rbx-compiler/compiler/ast/block.rb +70 -0
  27. data/boot/rbx-compiler/compiler/ast/class_def.rb +35 -0
  28. data/boot/rbx-compiler/compiler/ast/expression_list.rb +57 -0
  29. data/boot/rbx-compiler/compiler/ast/hash_literal.rb +11 -0
  30. data/boot/rbx-compiler/compiler/ast/identifier.rb +120 -0
  31. data/boot/rbx-compiler/compiler/ast/match.rb +81 -0
  32. data/boot/rbx-compiler/compiler/ast/message_send.rb +71 -0
  33. data/boot/rbx-compiler/compiler/ast/method_def.rb +116 -0
  34. data/boot/rbx-compiler/compiler/ast/node.rb +6 -0
  35. data/boot/rbx-compiler/compiler/ast/range_literal.rb +22 -0
  36. data/boot/rbx-compiler/compiler/ast/require.rb +20 -0
  37. data/boot/rbx-compiler/compiler/ast/return.rb +29 -0
  38. data/boot/rbx-compiler/compiler/ast/ruby_args.rb +35 -0
  39. data/boot/rbx-compiler/compiler/ast/script.rb +56 -0
  40. data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +39 -0
  41. data/boot/rbx-compiler/compiler/ast/string_literal.rb +14 -0
  42. data/boot/rbx-compiler/compiler/ast/super.rb +25 -0
  43. data/boot/rbx-compiler/compiler/ast/try_catch_block.rb +220 -0
  44. data/boot/rbx-compiler/compiler/ast/tuple_literal.rb +33 -0
  45. data/boot/rbx-compiler/compiler/command.rb +39 -0
  46. data/boot/rbx-compiler/compiler/compiler.rb +83 -0
  47. data/boot/rbx-compiler/compiler/stages.rb +99 -0
  48. data/boot/rbx-compiler/parser.rb +2 -0
  49. data/boot/rbx-compiler/parser/README +15 -0
  50. data/boot/rbx-compiler/parser/Rakefile +54 -0
  51. data/boot/rbx-compiler/parser/extconf.rb +3 -0
  52. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  53. data/boot/rbx-compiler/parser/fancy_parser.c +46 -0
  54. data/boot/rbx-compiler/parser/fancy_parser.h +8 -0
  55. data/boot/rbx-compiler/parser/lexer.lex +180 -0
  56. data/boot/rbx-compiler/parser/parser.rb +356 -0
  57. data/boot/rbx-compiler/parser/parser.y +711 -0
  58. data/boot/rsexp_pretty_printer.rb +76 -0
  59. data/doc/api/fancy.css +93 -0
  60. data/doc/api/fancy.jsonp +1 -0
  61. data/doc/api/fdoc.js +187 -0
  62. data/doc/api/index.html +57 -0
  63. data/doc/api/underscore-min.js +18 -0
  64. data/doc/features.md +228 -0
  65. data/examples/argv.fy +8 -0
  66. data/examples/arithmetic.fy +7 -0
  67. data/examples/armstrong_numbers.fy +33 -0
  68. data/examples/array.fy +52 -0
  69. data/examples/blocks.fy +15 -0
  70. data/examples/boolean.fy +24 -0
  71. data/examples/call_with_receiver.fy +9 -0
  72. data/examples/class.fy +68 -0
  73. data/examples/closures.fy +24 -0
  74. data/examples/constant_access.fy +15 -0
  75. data/examples/default_args.fy +17 -0
  76. data/examples/define_methods.fy +15 -0
  77. data/examples/documentation.fy +57 -0
  78. data/examples/documentation_formatters.fy +25 -0
  79. data/examples/echo.fy +16 -0
  80. data/examples/empty_catch.fy +4 -0
  81. data/examples/exception.fy +9 -0
  82. data/examples/factorial.fy +12 -0
  83. data/examples/fibonacci.fy +16 -0
  84. data/examples/files.fy +23 -0
  85. data/examples/finally.fy +5 -0
  86. data/examples/game_of_life.fy +148 -0
  87. data/examples/hashes.fy +7 -0
  88. data/examples/hello_world.fy +6 -0
  89. data/examples/html_generator.fy +54 -0
  90. data/examples/implicit_return.fy +3 -0
  91. data/examples/matchers.fy +6 -0
  92. data/examples/methods.fy +29 -0
  93. data/examples/nested_classes.fy +27 -0
  94. data/examples/nested_try.fy +9 -0
  95. data/examples/numbers.fy +12 -0
  96. data/examples/pattern_matching.fy +40 -0
  97. data/examples/person.fy +65 -0
  98. data/examples/project-euler/01.fy +8 -0
  99. data/examples/project-euler/02.fy +21 -0
  100. data/examples/project-euler/28.fy +33 -0
  101. data/examples/rbx/and_or.fy +7 -0
  102. data/examples/rbx/blocks.fy +22 -0
  103. data/examples/rbx/classes.fy +32 -0
  104. data/examples/rbx/hello.fy +8 -0
  105. data/examples/rbx/include.fy +12 -0
  106. data/examples/rbx/inherit.fy +11 -0
  107. data/examples/rbx/methods.fy +15 -0
  108. data/examples/rbx/nested_classes.fy +9 -0
  109. data/examples/rbx/require.fy +3 -0
  110. data/examples/rbx/strings.fy +5 -0
  111. data/examples/regex.fy +7 -0
  112. data/examples/require.fy +7 -0
  113. data/examples/retry.fy +12 -0
  114. data/examples/return.fy +13 -0
  115. data/examples/ruby_require.fy +7 -0
  116. data/examples/ruby_send.fy +3 -0
  117. data/examples/singleton_methods.fy +21 -0
  118. data/examples/stupid_quicksort.fy +12 -0
  119. data/examples/threads.fy +18 -0
  120. data/examples/tuple.fy +8 -0
  121. data/examples/webserver/webserver.fy +18 -0
  122. data/lib/argv.fy +36 -0
  123. data/lib/array.fy +207 -0
  124. data/lib/block.fy +88 -0
  125. data/lib/boot.fy +41 -0
  126. data/lib/class.fy +106 -0
  127. data/lib/compiler.fy +14 -0
  128. data/lib/compiler/ast.fy +40 -0
  129. data/lib/compiler/ast/assign.fy +96 -0
  130. data/lib/compiler/ast/block.fy +84 -0
  131. data/lib/compiler/ast/class_def.fy +33 -0
  132. data/lib/compiler/ast/expression_list.fy +47 -0
  133. data/lib/compiler/ast/identifier.fy +113 -0
  134. data/lib/compiler/ast/literals.fy +122 -0
  135. data/lib/compiler/ast/match.fy +88 -0
  136. data/lib/compiler/ast/message_send.fy +110 -0
  137. data/lib/compiler/ast/method_def.fy +90 -0
  138. data/lib/compiler/ast/node.fy +7 -0
  139. data/lib/compiler/ast/range.fy +16 -0
  140. data/lib/compiler/ast/require.fy +15 -0
  141. data/lib/compiler/ast/return.fy +23 -0
  142. data/lib/compiler/ast/script.fy +52 -0
  143. data/lib/compiler/ast/singleton_method_def.fy +35 -0
  144. data/lib/compiler/ast/super.fy +17 -0
  145. data/lib/compiler/ast/try_catch.fy +176 -0
  146. data/lib/compiler/ast/tuple_literal.fy +34 -0
  147. data/lib/compiler/command.fy +51 -0
  148. data/lib/compiler/compiler.fy +73 -0
  149. data/lib/compiler/stages.fy +81 -0
  150. data/lib/directory.fy +17 -0
  151. data/lib/documentation.fy +115 -0
  152. data/lib/enumerable.fy +269 -0
  153. data/lib/eval.fy +31 -0
  154. data/lib/fancy_spec.fy +202 -0
  155. data/lib/fdoc.fy +359 -0
  156. data/lib/fdoc_hook.fy +10 -0
  157. data/lib/file.fy +54 -0
  158. data/lib/hash.fy +56 -0
  159. data/lib/main.fy +80 -0
  160. data/lib/method.fy +22 -0
  161. data/lib/nil_class.fy +56 -0
  162. data/lib/number.fy +87 -0
  163. data/lib/object.fy +170 -0
  164. data/lib/package.fy +61 -0
  165. data/lib/package/dependency.fy +24 -0
  166. data/lib/package/installer.fy +180 -0
  167. data/lib/package/specification.fy +55 -0
  168. data/lib/package/uninstaller.fy +15 -0
  169. data/lib/parser.fy +4 -0
  170. data/lib/parser/ext/README +15 -0
  171. data/lib/parser/ext/ext.c +42 -0
  172. data/lib/parser/ext/ext.h +8 -0
  173. data/lib/parser/ext/extconf.rb +3 -0
  174. data/lib/parser/ext/lexer.lex +187 -0
  175. data/lib/parser/ext/parser.y +744 -0
  176. data/lib/parser/methods.fy +297 -0
  177. data/lib/rbx.fy +37 -0
  178. data/lib/rbx/array.fy +237 -0
  179. data/lib/rbx/bignum.fy +23 -0
  180. data/lib/rbx/block.fy +9 -0
  181. data/lib/rbx/class.fy +129 -0
  182. data/lib/rbx/code_loader.fy +192 -0
  183. data/lib/rbx/console.fy +63 -0
  184. data/lib/rbx/directory.fy +46 -0
  185. data/lib/rbx/documentation.fy +64 -0
  186. data/lib/rbx/environment_variables.fy +3 -0
  187. data/lib/rbx/exception.fy +30 -0
  188. data/lib/rbx/false_class.fy +58 -0
  189. data/lib/rbx/fiber.fy +25 -0
  190. data/lib/rbx/file.fy +191 -0
  191. data/lib/rbx/fixnum.fy +25 -0
  192. data/lib/rbx/float.fy +14 -0
  193. data/lib/rbx/hash.fy +38 -0
  194. data/lib/rbx/integer.fy +15 -0
  195. data/lib/rbx/io.fy +30 -0
  196. data/lib/rbx/match_data.fy +9 -0
  197. data/lib/rbx/method.fy +22 -0
  198. data/lib/rbx/name_error.fy +3 -0
  199. data/lib/rbx/no_method_error.fy +15 -0
  200. data/lib/rbx/object.fy +117 -0
  201. data/lib/rbx/range.fy +15 -0
  202. data/lib/rbx/regexp.fy +9 -0
  203. data/lib/rbx/string.fy +63 -0
  204. data/lib/rbx/symbol.fy +12 -0
  205. data/lib/rbx/system.fy +37 -0
  206. data/lib/rbx/tcp_server.fy +6 -0
  207. data/lib/rbx/tcp_socket.fy +7 -0
  208. data/lib/rbx/thread.fy +75 -0
  209. data/lib/rbx/tuple.fy +37 -0
  210. data/lib/set.fy +61 -0
  211. data/lib/stack.fy +51 -0
  212. data/lib/string.fy +58 -0
  213. data/lib/struct.fy +13 -0
  214. data/lib/symbol.fy +23 -0
  215. data/lib/true_class.fy +43 -0
  216. data/lib/tuple.fy +68 -0
  217. data/lib/version.fy +6 -0
  218. data/tests/argv.fy +13 -0
  219. data/tests/array.fy +343 -0
  220. data/tests/assignment.fy +53 -0
  221. data/tests/block.fy +103 -0
  222. data/tests/class.fy +409 -0
  223. data/tests/control_flow.fy +79 -0
  224. data/tests/documentation.fy +24 -0
  225. data/tests/exception.fy +115 -0
  226. data/tests/file.fy +86 -0
  227. data/tests/hash.fy +101 -0
  228. data/tests/method.fy +131 -0
  229. data/tests/nil_class.fy +55 -0
  230. data/tests/number.fy +128 -0
  231. data/tests/object.fy +125 -0
  232. data/tests/parsing/sexp.fy +50 -0
  233. data/tests/pattern_matching.fy +82 -0
  234. data/tests/range.fy +11 -0
  235. data/tests/set.fy +10 -0
  236. data/tests/stack.fy +22 -0
  237. data/tests/string.fy +102 -0
  238. data/tests/symbol.fy +17 -0
  239. data/tests/true_class.fy +63 -0
  240. data/tests/tuple.fy +21 -0
  241. data/tools/fancy-mode.el +63 -0
  242. 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
+ }