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,53 @@
1
+ FancySpec describe: "Assignment" with: {
2
+ it: "should correctly assign multiple values at once" when: {
3
+ x, y, z = 1, 10, 100
4
+ x should == 1
5
+ y should == 10
6
+ z should == 100
7
+
8
+ x, y, z = 'foo, 'bar
9
+ x should == 'foo
10
+ y should == 'bar
11
+ z should == nil
12
+
13
+ x = 'foo
14
+ y = 'bar
15
+ x, y = y, x
16
+ x should == 'bar
17
+ y should == 'foo
18
+ }
19
+
20
+ it: "should handle multiple assignment for any collection type implementing 'at:" when: {
21
+ x, y, z = (1, 2, 3)
22
+ x should == 1
23
+ y should == 2
24
+ z should == 3
25
+
26
+ a, b, c = ["a", "b", "c"]
27
+ a should == "a"
28
+ b should == "b"
29
+ c should == "c"
30
+
31
+ e, f = ([1,2], "foo")
32
+ e should == [1,2]
33
+ f should == "foo"
34
+ }
35
+
36
+ it: "should handle multiple assignment with splat-identifiers" when: {
37
+ x,y,z,*rest = [1,2,3,4,5,6,7]
38
+ x should == 1
39
+ y should == 2
40
+ z should == 3
41
+ rest should == [4,5,6,7]
42
+
43
+ a,b,*c,*d,e = [1,2,3,4,5,6,7,8]
44
+ a should == 1
45
+ b should == 2
46
+ c should == [3,4,5,6,7,8]
47
+ d should == [4,5,6,7,8]
48
+ e should == 5
49
+
50
+ _,_,*z = "hello, world!" # ignore first 2 characters
51
+ z should == "llo, world!"
52
+ }
53
+ }
data/tests/block.fy ADDED
@@ -0,0 +1,103 @@
1
+ FancySpec describe: Block with: {
2
+ it: "should return the value of the last expression" when: {
3
+ block = {
4
+ a = "a"
5
+ empty = " "
6
+ str = "String!"
7
+ a ++ empty ++ str
8
+ }
9
+ block call should == "a String!"
10
+ }
11
+
12
+ it: "should close over a value and change it internally" when: {
13
+ x = 0
14
+ { x < 10 } while_true: {
15
+ x should be: |x| { x < 10 }
16
+ x = x + 1
17
+ }
18
+ x should == 10
19
+ }
20
+
21
+ it: "should return the argument count" for: 'argcount when: {
22
+ { } argcount . should == 0
23
+ |x| { } argcount . should == 1
24
+ |x y z| { } argcount . should == 3
25
+ }
26
+
27
+ it: "should call a block while another is true" for: 'while_true: when: {
28
+ i = 0
29
+ {i < 10} while_true: {
30
+ i = i + 1
31
+ }
32
+ i should be: { i >= 10 }
33
+ }
34
+
35
+ it: "should call a block while another is not true (boolean false)" for: 'while_false: when: {
36
+ i = 0
37
+ {i == 10} while_false: {
38
+ i = i + 1
39
+ }
40
+ i should == 10
41
+ }
42
+
43
+ # again for while_nil
44
+ it: "should call a block while another is nil" for: 'while_nil: when: {
45
+ i = 0
46
+ {i == 10} while_nil: {
47
+ i = i + 1
48
+ }
49
+ i should == 10
50
+ }
51
+
52
+ it: "should call a block while another one is true-ish" for: 'while_do: when: {
53
+ x = 0
54
+ { x < 10 } while_do: |val| {
55
+ val should == true
56
+ x = x + 1
57
+ }
58
+ }
59
+
60
+ it: "should call itself only when the argument is nil" for: 'unless: when: {
61
+ try {
62
+ { StdError new: "got_run!" . raise! } unless: nil
63
+ StdError new: "didnt_run!" . raise!
64
+ } catch StdError => e {
65
+ e message should == "got_run!"
66
+ }
67
+ }
68
+
69
+ it: "should call itself only when the argument is true" for: 'if: when: {
70
+ try {
71
+ { StdError new: "got_run!" . raise! } if: true
72
+ StdError new: "didnt_run!" . raise!
73
+ } catch StdError => e {
74
+ e message should == "got_run!"
75
+ }
76
+ }
77
+
78
+ it: "should also be able to take arguments seperated by comma" for: 'call: when: {
79
+ block = |x, y| { x + y }
80
+ block call: [1,2] . should == 3
81
+ }
82
+
83
+ it: "should evaluate the blocks in a short-circuiting manner" for: '&& when: {
84
+ { false } && { false } should == false
85
+ { true } && { false } should == false
86
+ { false } && { true } should == false
87
+ { true } && { true } should == true
88
+
89
+ { false } || { false } should == false
90
+ { false } || { true } should == true
91
+ { true } || { false } should == true
92
+ { true } || { true } should == true
93
+
94
+ # TODO: Add more useful tests here...
95
+ }
96
+
97
+ it: "should call the block as a partial block" when: {
98
+ [1,2,3] map: @{upto: 3} . should == [[1,2,3], [2,3], [3]]
99
+ [1,2,3] map: @{+ 3} . should == [4,5,6]
100
+ [1,2,3] map: @{to_s} . should == ["1", "2", "3"]
101
+ [1,2,3] map: @{to_s * 3} . should == ["111", "222", "333"]
102
+ }
103
+ }
data/tests/class.fy ADDED
@@ -0,0 +1,409 @@
1
+ class Mixin {
2
+ def mixin_method {
3
+ 'mixed_in_found
4
+ }
5
+ }
6
+
7
+ class ClassWithMixin {
8
+ def normal_method {
9
+ 'normal_found
10
+ }
11
+ }
12
+
13
+ class ClassWithNoMixin {
14
+ read_slots: ['foo, 'bar, 'baz]
15
+ write_slots: ['hello, 'world]
16
+ read_write_slots: ['oh, 'noes]
17
+
18
+ def normal_method {
19
+ 'new_normal_found
20
+ }
21
+ }
22
+
23
+ class ClassWithPrivate {
24
+ def public_method {
25
+ "public!"
26
+ }
27
+
28
+ def protected protected_method {
29
+ "protected!"
30
+ }
31
+
32
+ def private private_method {
33
+ "private!"
34
+ }
35
+ }
36
+
37
+ FancySpec describe: Class with: {
38
+ it: "should NOT find the method when not mixed-in" for: 'responds_to?: when: {
39
+ instance = ClassWithMixin new
40
+ instance normal_method . should == 'normal_found
41
+ instance responds_to?: 'normal_method . should == true
42
+ instance responds_to?: 'mixin_method . should == false
43
+ }
44
+
45
+ it: "should find the method when mixed-in" for: 'include: when: {
46
+ # => include Mixin into ClassWithMixin
47
+ class ClassWithMixin {
48
+ include: Mixin
49
+ }
50
+
51
+ instance = ClassWithMixin new
52
+ instance responds_to?: 'normal_method . should == true
53
+ instance responds_to?: 'mixin_method . should == true
54
+ instance normal_method . should == 'normal_found
55
+ instance mixin_method . should == 'mixed_in_found
56
+ }
57
+
58
+ it: "should rebind the old class name with ClassWithNoMixin and replace the old normal_method" when: {
59
+ instance = ClassWithMixin new
60
+ instance normal_method should == 'normal_found
61
+ # rebind the class to the other class
62
+ ClassWithMixin = ClassWithNoMixin
63
+ instance = ClassWithMixin new
64
+ instance normal_method should == 'new_normal_found
65
+ }
66
+
67
+ it: "should have dynamically generated getter methods" for: 'responds_to?: when: {
68
+ instance = ClassWithNoMixin new
69
+ instance responds_to?: 'foo . should == true
70
+ instance responds_to?: 'bar . should == true
71
+ instance responds_to?: 'baz . should == true
72
+ instance responds_to?: "hello:" . should == true
73
+ instance responds_to?: "world:" . should == true
74
+ instance responds_to?: 'oh . should == true
75
+ instance responds_to?: ":oh" . should == true
76
+ instance responds_to?: 'noes . should == true
77
+ instance responds_to?: "noes:" . should == true
78
+ }
79
+
80
+ it: "should find the instance variable correctly" when: {
81
+ class AClass {
82
+ def initialize: foo {
83
+ @foo = foo
84
+ }
85
+ def foo {
86
+ @foo
87
+ }
88
+ }
89
+
90
+ str = "instance value"
91
+ instance = AClass new: str
92
+ instance foo should == str
93
+ AClass new foo should == nil
94
+ }
95
+
96
+ it: "should find the class variable correctly" when: {
97
+ class AClass {
98
+ def foo: foo {
99
+ @@foo = foo
100
+ }
101
+ def foo {
102
+ @@foo
103
+ }
104
+ }
105
+
106
+ instance1 = AClass new
107
+ instance2 = AClass new
108
+ str = "class value"
109
+ instance1 foo: str
110
+ instance1 foo should == str
111
+ instance2 foo should == str
112
+ instance2 foo should == (instance1 foo)
113
+
114
+ str2 = "another value"
115
+ instance2 foo: str2
116
+ instance2 foo should == str2
117
+ instance1 foo should == str2
118
+ }
119
+
120
+ it: "should have correct method overloading for method names with and without an argument" when: {
121
+ class AClass {
122
+ def foo {
123
+ foo: "None!"
124
+ }
125
+
126
+ def foo: bar {
127
+ "In AClass#foo: with bar = " ++ bar
128
+ }
129
+ }
130
+
131
+ instance = AClass new
132
+ instance foo should == "In AClass#foo: with bar = None!"
133
+ instance foo: "Test!" . should == "In AClass#foo: with bar = Test!"
134
+ }
135
+
136
+ # it: "should call superclass method by calling super" when: {
137
+ # class SuperClass {
138
+ # read_slots: ['name]
139
+ # def initialize: name {
140
+ # @name = name
141
+ # }
142
+ # }
143
+ # class SubClass : SuperClass {
144
+ # read_slots: ['age]
145
+
146
+ # def initialize: age {
147
+ # super initialize: "SubClass"
148
+ # @age = age
149
+ # }
150
+ # def initialize {
151
+ # super initialize: "SubClass"
152
+ # @age = 0
153
+ # }
154
+ # }
155
+
156
+ # sub = SubClass new: 42
157
+ # sub name should == "SubClass"
158
+ # sub age should == 42
159
+
160
+ # sub2 = SubClass new
161
+ # sub2 name should == "SubClass"
162
+ # sub2 age should == 0
163
+ # }
164
+
165
+ it: "should return its superclass" when: {
166
+ Fixnum superclass should == Integer
167
+ Symbol superclass should == Object
168
+ StdError superclass should == Exception
169
+ Class superclass should == Module
170
+ Object superclass should == nil
171
+
172
+ IOError superclass should == StandardError
173
+ NoMethodError superclass should == NameError
174
+ }
175
+
176
+ # it: "should create a new Class dynamically" when: {
177
+ # x = Class new
178
+ # x is_a?: Class . should == true
179
+ # x new is_a?: x . should == true
180
+ # x new is_a?: Object . should == true
181
+ # x new class should == x
182
+
183
+ # # Symbol as superclass
184
+ # y = Class new: Symbol
185
+ # y is_a?: Class . should == true
186
+ # y new is_a?: Symbol . should == true
187
+ # y new is_a?: Object . should == true
188
+ # }
189
+
190
+ it: "should only be able to call the public method from outside the Class" when: {
191
+ x = ClassWithPrivate new
192
+ x public_method should == "public!"
193
+ try {
194
+ x private_method should == nil # should fail
195
+ } catch NoMethodError => e {
196
+ e method_name should == "private_method"
197
+ }
198
+ try {
199
+ x protected_method should == nil # should fail
200
+ } catch NoMethodError => e {
201
+ e method_name should == "protected_method"
202
+ }
203
+ }
204
+
205
+ it: "should be a subclass of another Class" for: 'subclass?: when: {
206
+ class Super {
207
+ }
208
+ class Sub : Super {
209
+ }
210
+
211
+ Super subclass?: Object . should == true
212
+ Sub subclass?: Object . should == true
213
+ Sub subclass?: Super . should == true
214
+ Super subclass?: Sub . should == nil
215
+ }
216
+
217
+ # it: "should dynamically create a subclass of another class" for: 'is_a?: when: {
218
+ # subclass = String subclass: {
219
+ # def foo {
220
+ # "hello, world!"
221
+ # }
222
+ # }
223
+ # subclass is_a?: Class . should == true
224
+ # subclass subclass?: String . should == true
225
+ # subclass new is_a?: subclass . should == true
226
+ # subclass new foo should == "hello, world!"
227
+
228
+ # # now the same with Class##new:body:
229
+ # subclass2 = Class superclass: Symbol body: {
230
+ # def foo {
231
+ # "hello, world, again!"
232
+ # }
233
+ # }
234
+ # subclass2 is_a?: Class . should == true
235
+ # subclass2 subclass?: String . should == true
236
+ # subclass2 new is_a?: subclass2 . should == true
237
+ # subclass2 new foo should == "hello, world, again!"
238
+ # }
239
+
240
+ it: "should undefine an instance method" for: 'undefine_method: when: {
241
+ class Foo {
242
+ def instance_method {
243
+ "instance method!"
244
+ }
245
+ }
246
+ f = Foo new
247
+ f instance_method should == "instance method!"
248
+ Foo undefine_method: 'instance_method
249
+ try {
250
+ f instance_method should == nil # should not get here
251
+ } catch NoMethodError => e {
252
+ e method_name should == "instance_method"
253
+ }
254
+ }
255
+
256
+ it: "should undefine a class method" for: 'undefine_class_method: when: {
257
+ class Foo {
258
+ def self class_method {
259
+ "class method!"
260
+ }
261
+ }
262
+ Foo class_method should == "class method!"
263
+
264
+ try {
265
+ Foo undefine_method: 'class_method
266
+ true should == nil # should not happen
267
+ } catch NameError {
268
+ true should == true
269
+ }
270
+
271
+ Foo undefine_class_method: 'class_method
272
+
273
+ try {
274
+ Foo class_method should == nil # should not get here
275
+ } catch NoMethodError => e {
276
+ e method_name should == "class_method"
277
+ }
278
+ }
279
+
280
+ # it: "should have nested classes" when: {
281
+ # class Outer {
282
+ # class Inner {
283
+ # class InnerMost {
284
+ # def foobar {
285
+ # "foobar!"
286
+ # }
287
+ # }
288
+ # }
289
+ # }
290
+ # Outer is_a?: Class . should == true
291
+ # Outer::Inner is_a?: Class . should == true
292
+ # Outer::Inner::InnerMost is_a?: Class . should == true
293
+ # obj = Outer::Inner::InnerMost new
294
+ # obj foobar should == "foobar!"
295
+
296
+ # # change InnerMost#foobar
297
+ # class Outer::Inner::InnerMost {
298
+ # def foobar {
299
+ # "oh no!"
300
+ # }
301
+ # }
302
+ # obj foobar . should == "oh no!"
303
+ # }
304
+
305
+ it: "should not override existing classes with the same name in a nested class" when: {
306
+ StdArray = Array
307
+ class NameSpace {
308
+ class Array {
309
+ def Array what_am_i {
310
+ "not the same as the standard Array class"
311
+ }
312
+ }
313
+ }
314
+
315
+ NameSpace::Array what_am_i . should == "not the same as the standard Array class"
316
+ NameSpace::Array should_not == Array
317
+ }
318
+
319
+ # it: "should return all nested classes of a class" for: 'nested_classes when: {
320
+ # class Outer {
321
+ # }
322
+ # Outer nested_classes should == []
323
+
324
+ # class Outer {
325
+ # class Inner1 {
326
+ # }
327
+ # }
328
+ # Outer nested_classes should == [Outer::Inner1]
329
+
330
+ # class Outer {
331
+ # class Inner2 {
332
+ # }
333
+ # }
334
+ # Outer nested_classes should == [Outer::Inner1, Outer::Inner2]
335
+ # }
336
+
337
+ it: "should find other nested classes in the same parent class" when: {
338
+ class MyOuter {
339
+ class Inner1 {
340
+ def method1 {
341
+ 'method_1
342
+ }
343
+ }
344
+ class Inner2 {
345
+ include: Inner1
346
+ def method2 {
347
+ 'method_2
348
+ }
349
+ }
350
+ }
351
+
352
+ MyOuter::Inner1 new method1 should == 'method_1
353
+ MyOuter::Inner2 new method1 should == 'method_1
354
+ MyOuter::Inner2 new method2 should == 'method_2
355
+ }
356
+
357
+ it: "should find itself in it's own methods, even if nested into another class" when: {
358
+ class MyOuter {
359
+ class MyInner1 {
360
+ def method1 {
361
+ MyInner1
362
+ }
363
+ def self class_method1 {
364
+ MyInner1
365
+ }
366
+ }
367
+ class MyInner2 {
368
+ def method2 {
369
+ [MyInner1, MyInner2]
370
+ }
371
+ def self class_method2 {
372
+ [MyInner1, MyInner2]
373
+ }
374
+ }
375
+ }
376
+
377
+ MyOuter::MyInner1 new method1 should == MyOuter::MyInner1
378
+ MyOuter::MyInner2 new method2 should == [MyOuter::MyInner1, MyOuter::MyInner2]
379
+ MyOuter::MyInner1 class_method1 should == MyOuter::MyInner1
380
+ MyOuter::MyInner2 class_method2 should == [MyOuter::MyInner1, MyOuter::MyInner2]
381
+ }
382
+
383
+ it: "should have an alias method as defined" for: 'alias_method:for: when: {
384
+ class AClass {
385
+ def foo {
386
+ "in foo!"
387
+ }
388
+
389
+ alias_method: 'bar for: 'foo
390
+ }
391
+
392
+ obj = AClass new
393
+ obj foo should == "in foo!"
394
+ obj bar should == "in foo!"
395
+ }
396
+
397
+ it: "should have the correct list of ancestors" for: 'ancestors when: {
398
+ class A {
399
+ }
400
+ class B : A {
401
+ }
402
+ class C : B {
403
+ }
404
+
405
+ A ancestors should == [A, Object, Kernel]
406
+ B ancestors should == [B, A, Object, Kernel]
407
+ C ancestors should == [C, B, A, Object, Kernel]
408
+ }
409
+ }