fancy 0.8.0 → 0.9.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 (111) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +5 -4
  3. data/bin/fspec +19 -1
  4. data/bin/ifancy +139 -35
  5. data/boot/README +2 -9
  6. data/boot/extconf.rb +0 -1
  7. data/boot/fancy_ext/module.rb +5 -15
  8. data/boot/fancy_ext/thread.rb +22 -9
  9. data/boot/rbx-compiler/README +0 -4
  10. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  11. data/boot/rbx-compiler/parser/parser.y +1 -0
  12. data/doc/api/fancy.css +1 -6
  13. data/doc/api/fancy.jsonp +1 -1
  14. data/doc/api/fdoc.js +2 -4
  15. data/doc/api/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  16. data/doc/api/images/ui-bg_flat_0_eeeeee_40x100.png +0 -0
  17. data/doc/api/images/ui-bg_flat_55_ffffff_40x100.png +0 -0
  18. data/doc/api/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  19. data/doc/api/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  20. data/doc/api/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png +0 -0
  21. data/doc/api/images/ui-bg_highlight-soft_25_0073ea_1x100.png +0 -0
  22. data/doc/api/images/ui-bg_highlight-soft_50_dddddd_1x100.png +0 -0
  23. data/doc/api/images/ui-icons_0073ea_256x240.png +0 -0
  24. data/doc/api/images/ui-icons_454545_256x240.png +0 -0
  25. data/doc/api/images/ui-icons_666666_256x240.png +0 -0
  26. data/doc/api/images/ui-icons_ff0084_256x240.png +0 -0
  27. data/doc/api/images/ui-icons_ffffff_256x240.png +0 -0
  28. data/doc/api/index.html +5 -4
  29. data/doc/api/jquery-1.8.2.min.js +2 -0
  30. data/doc/api/jquery-ui-1.9.0.custom.min.css +5 -0
  31. data/doc/api/jquery-ui-1.9.0.custom.min.js +6 -0
  32. data/doc/features.md +8 -3
  33. data/examples/argv.fy +1 -1
  34. data/examples/closures.fy +1 -4
  35. data/examples/echo.fy +2 -2
  36. data/examples/guess_number.fy +18 -0
  37. data/examples/nested_classes.fy +3 -15
  38. data/lib/argv.fy +23 -18
  39. data/lib/array.fy +18 -37
  40. data/lib/block.fy +125 -0
  41. data/lib/boot.fy +1 -0
  42. data/lib/compiler/ast/block.fy +1 -1
  43. data/lib/compiler/ast/identifier.fy +1 -1
  44. data/lib/compiler/ast/message_send.fy +0 -13
  45. data/lib/compiler/ast/method_def.fy +1 -1
  46. data/lib/compiler/ast/singleton_method_def.fy +1 -0
  47. data/lib/compiler/ast/tuple_literal.fy +1 -1
  48. data/lib/compiler/command.fy +1 -1
  49. data/lib/compiler/compiler.fy +8 -6
  50. data/lib/contracts.fy +1 -1
  51. data/lib/directory.fy +1 -1
  52. data/lib/dynamic_slot_object.fy +1 -1
  53. data/lib/enumerable.fy +316 -25
  54. data/lib/enumerator.fy +11 -8
  55. data/lib/eval.fy +0 -3
  56. data/lib/fancy_spec.fy +27 -0
  57. data/lib/fdoc.fy +8 -8
  58. data/lib/file.fy +25 -1
  59. data/lib/hash.fy +91 -0
  60. data/lib/html.fy +40 -11
  61. data/lib/integer.fy +4 -0
  62. data/lib/main.fy +18 -11
  63. data/lib/object.fy +33 -7
  64. data/lib/option_parser.fy +20 -1
  65. data/lib/package/dependency.fy +8 -0
  66. data/lib/package/dependency_installer.fy +3 -6
  67. data/lib/package/handler.fy +4 -4
  68. data/lib/package/installer.fy +2 -5
  69. data/lib/package/list.fy +3 -4
  70. data/lib/parser/ext/parser.y +1 -0
  71. data/lib/proxies.fy +0 -2
  72. data/lib/queue.fy +7 -0
  73. data/lib/rbx.fy +1 -0
  74. data/lib/rbx/actor.fy +3 -1
  75. data/lib/rbx/alpha.fy +24 -0
  76. data/lib/rbx/array.fy +3 -1
  77. data/lib/rbx/class.fy +5 -8
  78. data/lib/rbx/date_time.fy +14 -0
  79. data/lib/rbx/file.fy +6 -0
  80. data/lib/rbx/hash.fy +42 -0
  81. data/lib/rbx/thread.fy +5 -7
  82. data/lib/string.fy +56 -4
  83. data/lib/symbol.fy +29 -1
  84. data/lib/time.fy +17 -0
  85. data/lib/vars.fy +4 -3
  86. data/lib/version.fy +1 -1
  87. data/ruby_lib/interactive/hilight.rb +125 -0
  88. data/tests/array.fy +19 -7
  89. data/tests/block.fy +103 -4
  90. data/tests/class.fy +31 -26
  91. data/tests/control_flow.fy +0 -1
  92. data/tests/dynamic_key_hash.fy +22 -1
  93. data/tests/enumerable.fy +239 -7
  94. data/tests/enumerator.fy +7 -0
  95. data/tests/file.fy +16 -0
  96. data/tests/future.fy +1 -11
  97. data/tests/future_proxy.fy +8 -0
  98. data/tests/hash.fy +132 -9
  99. data/tests/html.fy +30 -13
  100. data/tests/integer.fy +3 -0
  101. data/tests/method.fy +6 -11
  102. data/tests/object.fy +12 -5
  103. data/tests/option_parser.fy +12 -3
  104. data/tests/string.fy +69 -1
  105. data/tests/symbol.fy +24 -0
  106. metadata +42 -12
  107. data/boot/rsexp_pretty_printer.rb +0 -76
  108. data/doc/api/jquery-ui.min.js +0 -401
  109. data/doc/api/jquery.tools.min.js +0 -192
  110. data/doc/api/themeswitchertool.js +0 -250
  111. data/examples/future_sends.fy +0 -15
data/lib/enumerator.fy CHANGED
@@ -1,5 +1,13 @@
1
1
  class Fancy {
2
2
  class Enumerator {
3
+ class Generator {
4
+ def initialize: @block
5
+
6
+ def each: block {
7
+ @block call: [block]
8
+ }
9
+ }
10
+
3
11
  def initialize: @collection {
4
12
  """
5
13
  @collection Collection to iterate over.
@@ -141,6 +149,8 @@ class Fancy {
141
149
  }
142
150
  }
143
151
 
152
+ include: Fancy Enumerable
153
+
144
154
  def chunk: block {
145
155
  Generator new: |inner_block| {
146
156
  enums = []
@@ -169,17 +179,10 @@ class Fancy {
169
179
  } . to_enum
170
180
  }
171
181
 
172
- class Generator {
173
- def initialize: @block {}
174
-
175
- def each: block {
176
- @block call: [block]
177
- }
178
- }
179
-
180
182
  def to_a {
181
183
  output = []
182
184
  each: |element| { output << element }
185
+ rewind
183
186
  output
184
187
  }
185
188
  }
data/lib/eval.fy CHANGED
@@ -27,7 +27,6 @@ def Fancy eval: code binding: binding (nil) file: file ("(fancy-eval)") line: li
27
27
  cm name=('__fancy_eval__)
28
28
 
29
29
  script = Rubinius CompiledMethod Script new(cm, file, true)
30
- script eval_binding=(binding)
31
30
  script eval_source=(code)
32
31
 
33
32
  cm scope() script=(script)
@@ -39,7 +38,5 @@ def Fancy eval: code binding: binding (nil) file: file ("(fancy-eval)") line: li
39
38
  be proc_environment=(binding proc_environment)
40
39
  }
41
40
 
42
- be from_eval!()
43
-
44
41
  be call()
45
42
  }
data/lib/fancy_spec.fy CHANGED
@@ -13,6 +13,8 @@ class FancySpec {
13
13
  @spec_tests = []
14
14
  @before_blocks = []
15
15
  @after_blocks = []
16
+ @before_all_block = {}
17
+ @after_all_block = {}
16
18
  }
17
19
 
18
20
  def FancySpec describe: test_obj with: block {
@@ -94,6 +96,22 @@ class FancySpec {
94
96
 
95
97
  alias_method: 'it:for:when: for: 'it:with:when:
96
98
 
99
+ def before: block {
100
+ """
101
+ @block @Block@ to be run before all test cases.
102
+ """
103
+
104
+ @before_all_block = block
105
+ }
106
+
107
+ def after: block {
108
+ """
109
+ @block @Block@ to be run after all test cases.
110
+ """
111
+
112
+ @after_all_block = block
113
+ }
114
+
97
115
  def before_each: block {
98
116
  """
99
117
  @block @Block@ to be run before each test case.
@@ -116,6 +134,9 @@ class FancySpec {
116
134
  """
117
135
 
118
136
  # " " ++ @description ++ ": " print
137
+
138
+ @before_all_block call
139
+
119
140
  @spec_tests each: |test| {
120
141
  @before_blocks each: |b| {
121
142
  b call_with_receiver: test
@@ -126,6 +147,8 @@ class FancySpec {
126
147
  }
127
148
  }
128
149
 
150
+ @after_all_block call
151
+
129
152
  # untested_methods = @test_obj methods select: |m| {
130
153
  # m tests size == 0
131
154
  # }
@@ -431,6 +454,10 @@ class Object {
431
454
  is == expected
432
455
  }
433
456
 
457
+ def is_a: class {
458
+ is_a?: class . is: true
459
+ }
460
+
434
461
  def is_not: expected {
435
462
  does_not == expected
436
463
  }
data/lib/fdoc.fy CHANGED
@@ -133,7 +133,7 @@ class Fancy FDoc {
133
133
  keys each: |i| {
134
134
  str << $ to_json: i
135
135
  str << ":"
136
- str << $ to_json: (obj at: i)
136
+ str << $ to_json: (obj[i])
137
137
  } in_between: { str << ", " }
138
138
  str << "}"
139
139
  str join
@@ -162,7 +162,7 @@ class Fancy FDoc {
162
162
  if: mdoc then: {
163
163
  mattr['doc]: $ mdoc format: 'fdoc
164
164
  if: (mdoc meta) then: {
165
- mattr['arg]: $ mdoc meta at: 'argnames
165
+ mattr['arg]: $ mdoc meta['argnames]
166
166
  }
167
167
  }
168
168
  if: (exec class() == Rubinius CompiledMethod) then: {
@@ -176,7 +176,7 @@ class Fancy FDoc {
176
176
  # right now we only use the first line of code in the body.
177
177
  mattr['lines]: $ [exec definition_line, exec last_line]
178
178
  }
179
- attr[(type ++ "s") intern()] [n]: mattr
179
+ attr["#{type}s" intern()] [n to_s]: mattr
180
180
  }
181
181
  }
182
182
 
@@ -193,7 +193,7 @@ class Fancy FDoc {
193
193
  'doc => doc format: 'fdoc,
194
194
  'instance_methods => <[]>,
195
195
  'methods => <[]>,
196
- 'ancestors => cls ancestors() map: |c| { c name() gsub("::", " ") }
196
+ 'ancestors => cls ancestors() map: |c| { (c name || "") gsub("::", " ") }
197
197
  ]>
198
198
  popuplate_methods: cls on: attr type: 'instance_method known: methods
199
199
  popuplate_methods: cls on: attr type: 'method known: methods
@@ -202,14 +202,14 @@ class Fancy FDoc {
202
202
 
203
203
  methods each: |cm| {
204
204
  cls = cm scope() module()
205
- cls_name = cls name() gsub("::", " ")
206
- cls_attr = map['classes] at: cls_name
205
+ cls_name = cls name gsub("::", " ")
206
+ cls_attr = map['classes][cls_name]
207
207
 
208
- full_name = cls_name ++ "#" ++ (cm name())
208
+ full_name = "#{cls_name}##{cm name}"
209
209
 
210
210
  doc = Fancy Documentation for: cm
211
211
  attr = <[
212
- 'args => doc meta at: 'argnames,
212
+ 'args => doc meta['argnames],
213
213
  'doc => doc format: 'fdoc
214
214
  ]>
215
215
 
data/lib/file.fy CHANGED
@@ -15,6 +15,19 @@ class File {
15
15
  File open: filename modes: ['write] with: block
16
16
  }
17
17
 
18
+ def File overwrite: filename with: block {
19
+ """
20
+ @filename Filename of @File@ to overwrite.
21
+ @block @Block@ called with a @File@ object to write to (overwriting old contents.
22
+
23
+ Opens a @File@ for writing, overwriting old content.
24
+ """
25
+
26
+ File open: filename modes: ['truncate] with: block
27
+ }
28
+
29
+ metaclass alias_method: 'truncate:with: for: 'overwrite:with:
30
+
18
31
  def File append: filename with: block {
19
32
  """
20
33
  @filename Filename of @File@ to append to.
@@ -37,6 +50,17 @@ class File {
37
50
  File open: filename modes: ['read] with: block
38
51
  }
39
52
 
53
+ def File readlines: filename {
54
+ """
55
+ @filename Filename of @File@ to read lines from.
56
+ @return @Array@ of lines in @filename.
57
+
58
+ Opens & reads a @File@ and returns all of its lines in an @Array@.
59
+ """
60
+
61
+ File read: filename with: @{ readlines }
62
+ }
63
+
40
64
  def File read_binary: filename with: block {
41
65
  """
42
66
  @filename Filename of @File@ to read from.
@@ -122,7 +146,7 @@ class File {
122
146
  ]>
123
147
  """
124
148
 
125
- File read: filename . eval to_hash_deep
149
+ File eval: filename . to_hash_deep
126
150
  }
127
151
 
128
152
  def writeln: x {
data/lib/hash.fy CHANGED
@@ -139,6 +139,21 @@ class Hash {
139
139
  o
140
140
  }
141
141
 
142
+ def to_object_deep {
143
+ """
144
+ Similar to @Hash#to_object@ but converting any nested @Hash@ slots to @Object@s as well.
145
+ """
146
+
147
+ o = dup to_hash_deep to_object
148
+ o slots each: |s| {
149
+ val = o get_slot: s
150
+ match val {
151
+ case Hash >< Block -> o set_slot: s value: $ val to_object_deep
152
+ }
153
+ }
154
+ o
155
+ }
156
+
142
157
  def inspect {
143
158
  str = "<["
144
159
  each: |key val| {
@@ -152,6 +167,10 @@ class Hash {
152
167
  str
153
168
  }
154
169
 
170
+ def to_s {
171
+ inspect
172
+ }
173
+
155
174
  def values_at: keys {
156
175
  """
157
176
  @keys Collection of keys to get the values for.
@@ -276,4 +295,76 @@ class Hash {
276
295
  receiver
277
296
  }
278
297
  }
298
+
299
+ def update_values: block {
300
+ """
301
+ @block @Block@ that returns an updated value for each value in @self.
302
+
303
+ Example:
304
+ h = <['name => \"Tom\", 'age => 21 ]>
305
+ h update_values: @{ * 2}
306
+ h # => <['name => \”TomTom\”, 'age => 42]>
307
+ """
308
+
309
+ each: |k v| {
310
+ self[k]: $ block call: [v]
311
+ }
312
+ }
313
+
314
+ def update_keys: block {
315
+ """
316
+ @block @Block@ that returns an updated key for each key in @self.
317
+
318
+ Example:
319
+ h = <['name => \"Tom\", 'age => 21 ]>
320
+ h update_keys: @{ to_s * 2}
321
+ h # => <[\"namename\" => \”Tom\”, \"ageage\" => 21]>
322
+ """
323
+
324
+ deletions = []
325
+ insertions = <[]>
326
+
327
+ each: |k v| {
328
+ new_key = block call: [k]
329
+ if: (new_key != k) then: {
330
+ deletions << k
331
+ insertions[new_key]: v
332
+ }
333
+ }
334
+
335
+ deletions each: |k| { delete: k }
336
+ insertions each: |k v| {
337
+ self[k]: v
338
+ }
339
+ }
340
+
341
+ def with_updated_values: block {
342
+ """
343
+ @block @Block@ that returns an updated value for each value in @self.
344
+ @return @Hash@ based on self but with updated values via @block.
345
+ """
346
+
347
+ dup update_values: block
348
+ }
349
+
350
+ def with_updated_keys: block {
351
+ """
352
+ @block @Block@ that returns an updated key for each key in @self.
353
+ @return @Hash@ based on self but with updated keys via @block.
354
+ """
355
+
356
+ dup update_keys: block
357
+ }
358
+
359
+ def with_value_for_key: key do: block else: else_block ({}) {
360
+ """
361
+ @key Key of value to find in @self.
362
+ @block @Block@ to be called with value for @key, if found.
363
+ @else_block @Block@ to be called if @key not found in @self.
364
+ """
365
+
366
+ if: (includes?: key) then: {
367
+ block call: [at: key]
368
+ } else: else_block
369
+ }
279
370
  }
data/lib/html.fy CHANGED
@@ -34,16 +34,20 @@ class HTML {
34
34
  def initialize {
35
35
  @buf = ""
36
36
  @indent = 0
37
+ @indent_offset = 0
37
38
  }
38
39
 
39
- def initialize: block {
40
+ def initialize: block indentation: indent_offset (0) {
40
41
  initialize
42
+ @indent_offset = indent_offset
41
43
  block call: [self]
42
44
  }
43
45
 
46
+ def indentation: @indent_offset
47
+
44
48
  def open_tag: name attrs: attrs (<[]>) indent: indent (true) {
45
49
  @buf << "\n"
46
- @buf << (" " * @indent)
50
+ @buf << (" " * (@indent + @indent_offset))
47
51
  @indent = @indent + 2
48
52
 
49
53
  @buf << "<" << name
@@ -60,10 +64,10 @@ class HTML {
60
64
  { @indent = @indent - 2 } unless: indent
61
65
  }
62
66
 
63
- def close_tag: name {
64
- @buf << "\n"
67
+ def close_tag: name linebreak: linebreak (true) {
68
+ { @buf << "\n" } if: linebreak
65
69
  @indent = @indent - 2
66
- @buf << (" " * @indent)
70
+ @buf << (" " * (@indent + @indent_offset))
67
71
 
68
72
  @buf << "</" << name << ">"
69
73
  }
@@ -71,9 +75,10 @@ class HTML {
71
75
  def html_block: tag body: body attrs: attrs (<[]>) {
72
76
  tag = tag from: 0 to: -2
73
77
  open_tag: tag attrs: attrs
74
- match body first {
75
- case Block -> @buf << (body first call: [self])
76
- case _ -> @buf << "\n" << (" " * @indent) << (body first)
78
+ content = body first
79
+ match content {
80
+ case Block -> @buf << (content call: [self])
81
+ case _ -> @buf << "\n" << (" " * (@indent + @indent_offset)) << content
77
82
  }
78
83
  close_tag: tag
79
84
  nil
@@ -91,17 +96,41 @@ class HTML {
91
96
  }
92
97
 
93
98
  def br {
94
- @buf << "\n" << (" " * @indent)
99
+ @buf << "\n" << (" " * (@indent + @indent_offset))
95
100
  @buf << "<br/>"
96
101
  nil
97
102
  }
98
103
 
99
- def input: attrs {
100
- open_tag: "input" attrs: (attrs to_hash) indent: false
104
+ def script: attrs {
105
+ open_tag: "script" attrs: (attrs to_hash) indent: true
106
+ close_tag: "script" linebreak: false
107
+ nil
108
+ }
109
+
110
+ def textarea: attrs with: content ("") {
111
+ @buf << "\n" << (" " * (@indent + @indent_offset))
112
+ @buf << "<textarea "
113
+ attrs to_hash each: |name val| {
114
+ @buf << name << "=" << (val to_s inspect)
115
+ } in_between: {
116
+ @buf << " "
117
+ }
118
+ @buf << ">" << content << "</textarea>"
101
119
  nil
102
120
  }
103
121
 
104
122
  def to_s {
105
123
  @buf from: 1 to: -1 . to_s
106
124
  }
125
+
126
+ def self single_tags: single_tags {
127
+ single_tags each: |t| {
128
+ define_method: "#{t}:" with: |attrs| {
129
+ open_tag: t attrs: (attrs to_hash) indent: false
130
+ nil
131
+ }
132
+ }
133
+ }
134
+
135
+ single_tags: ('input, 'link, 'img)
107
136
  }
data/lib/integer.fy CHANGED
@@ -60,6 +60,10 @@ class Integer {
60
60
  12345 decimals # => [1, 2, 3, 4, 5]
61
61
  """
62
62
 
63
+ if: (self < 0) then: {
64
+ return negate decimals
65
+ }
66
+
63
67
  decimals = []
64
68
  tmp = self
65
69
  while: { tmp >= 10 } do: {
data/lib/main.fy CHANGED
@@ -7,7 +7,7 @@
7
7
  if: (ARGV size == 1) then: {
8
8
  ARGV for_options: ["-v", "--version"] do: {
9
9
  "Fancy #{Fancy VERSION}" println
10
- "(C) 2010, 2011, 2012 Christopher Bertels <chris@fancy-lang.org>" println
10
+ "(C) 2010, 2011, 2012, 2013 Christopher Bertels <chris@fancy-lang.org>" println
11
11
  System exit
12
12
  }
13
13
 
@@ -42,22 +42,29 @@ ARGV for_option: "-e" do: |eval_string| {
42
42
  }
43
43
 
44
44
  ARGV for_option: "-c" do: {
45
- ARGV index: "-c" . if_true: |idx| {
45
+ if: (ARGV index: "-c") then: |idx| {
46
46
  ARGV[[idx + 1, -1]] . tap: |filenames| {
47
- filenames each: |filename| {
48
- "Compiling " ++ filename println
49
- Fancy Compiler compile_file: filename to: nil line: 1 print: false
47
+ total = filenames size
48
+ max_width = total decimals size
49
+ start_time = Time now
50
+ duration = Time duration: {
51
+ filenames each_with_index: |filename idx| {
52
+ *stdout* printf("[%#{max_width}i / %i] Compiling %s\n", idx + 1, total, filename)
53
+ Fancy Compiler compile_file: filename to: nil line: 1 print: false
54
+ }
50
55
  }
51
- files = "file"
52
- { files = "files" } if: $ filenames size != 1
53
- "Compiled #{filenames size} #{files}." println
56
+ files = match filenames size {
57
+ case 1 -> "file"
58
+ case _ -> "files"
59
+ }
60
+ "Compiled #{filenames size} #{files} in #{duration} seconds." println
54
61
  }
55
62
  }
56
63
  System exit
57
64
  }
58
65
 
59
66
  ARGV for_option: "-cv" do: {
60
- ARGV index: "-cv" . if_true: |idx| {
67
+ if: (ARGV index: "-cv") then: |idx| {
61
68
  ARGV[[idx + 1, -1]] each: |filename| {
62
69
  "Compiling " ++ filename println
63
70
  Fancy Compiler compile_file: filename to: nil line: 1 print: true
@@ -92,7 +99,7 @@ ARGV for_option: "list-packages" do: {
92
99
  Fancy Package add_to_loadpath
93
100
 
94
101
  # Load a source file, if any given:
95
- ARGV first if_true: |file| {
102
+ if: (ARGV first) then: |file| {
96
103
  try {
97
104
  Fancy CodeLoader load_compiled_file: file
98
105
  } catch Fancy Parser ParseError => e {
@@ -100,6 +107,6 @@ ARGV first if_true: |file| {
100
107
  }
101
108
  }
102
109
 
103
- ARGV empty? if_true: {
110
+ if: (ARGV empty?) then: {
104
111
  require: "../bin/ifancy"
105
112
  }