fancy 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }