webfontloader 1.0.31 → 1.1.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 (34) hide show
  1. data/CHANGELOG +6 -0
  2. data/README.md +20 -3
  3. data/lib/webfontloader/demo/public/ascender-iframe.html +46 -0
  4. data/lib/webfontloader/demo/public/blank.html +9 -0
  5. data/lib/webfontloader/demo/public/custom-iframe.html +41 -0
  6. data/lib/webfontloader/demo/public/custom.html +10 -10
  7. data/lib/webfontloader/demo/public/google-iframe.html +40 -0
  8. data/lib/webfontloader/demo/public/index.html +15 -2
  9. data/lib/webfontloader/demo/public/monotype-iframe.html +46 -0
  10. data/lib/webfontloader/demo/public/typekit-iframe.html +41 -0
  11. data/lib/webfontloader/demo/public/typekit.html +7 -9
  12. data/lib/webfontloader.rb +1 -1
  13. data/src/ascender/ascender_script.js +2 -3
  14. data/src/core/domhelper.js +36 -4
  15. data/src/core/font.js +12 -6
  16. data/src/core/fontmoduleloader.js +2 -2
  17. data/src/core/initialize.js +2 -3
  18. data/src/custom/customcss.js +1 -2
  19. data/src/fontdeck/fontdeck_script.js +12 -10
  20. data/src/google/fontapiurlbuilder.js +1 -3
  21. data/src/google/googlefontapi.js +3 -4
  22. data/src/monotype/monotype_script.js +8 -25
  23. data/src/typekit/typekit_script.js +9 -10
  24. data/src-test/ascender/ascender_script_test.js +3 -0
  25. data/src-test/core/domhelpertest.js +44 -1
  26. data/src-test/core/eventdispatchertest.js +1 -1
  27. data/src-test/core/fonttest.js +53 -28
  28. data/src-test/fontdeck/fontdeck_script_test.js +26 -16
  29. data/src-test/google/fontapiurlbuildertest.js +5 -5
  30. data/src-test/google/googlefontapitest.js +12 -0
  31. data/src-test/monotype/monotype_script_test.js +36 -62
  32. data/src-test/typekit/typekit_script_test.js +30 -6
  33. data/webfontloader.gemspec +8 -2
  34. metadata +10 -4
@@ -41,6 +41,10 @@ FontdeckScriptTest.prototype.testSupportAndLoadLifecycle = function() {
41
41
  ]
42
42
  };
43
43
  var insert = '';
44
+ var global = {
45
+ // No hostname to verify fallback behavior for empty iframe
46
+ location: {}
47
+ };
44
48
  var src = '';
45
49
  var fakeDomHelper = {
46
50
  insertInto: function(tag, e) {
@@ -48,19 +52,22 @@ FontdeckScriptTest.prototype.testSupportAndLoadLifecycle = function() {
48
52
  },
49
53
  createScriptSrc: function(srcLink) {
50
54
  src = srcLink;
51
- }
52
- };
53
- var global = {
54
- location: {
55
- protocol: 'https:'
56
55
  },
57
- document: {
58
- location: {
59
- hostname: 'test-host-name'
60
- }
56
+ getLoadWindow: function() {
57
+ return global;
58
+ },
59
+ getMainWindow: function() {
60
+ return {
61
+ location: {
62
+ hostname: 'test-host-name'
63
+ }
64
+ };
65
+ },
66
+ getProtocol: function() {
67
+ return 'https:';
61
68
  }
62
69
  };
63
- var fontdeck = new webfont.FontdeckScript(global, fakeDomHelper, configuration);
70
+ var fontdeck = new webfont.FontdeckScript(fakeDomHelper, configuration);
64
71
 
65
72
  // supportUserAgent
66
73
  var userAgent = 'user agent';
@@ -80,7 +87,7 @@ FontdeckScriptTest.prototype.testSupportAndLoadLifecycle = function() {
80
87
  assertEquals(fontdeck.fontFamilies_, [apiResponse.fonts[0].name, apiResponse.fonts[1].name]);
81
88
  assertEquals(fontdeck.fontVariations_[apiResponse.fonts[0].name], ['n4']);
82
89
  assertEquals(fontdeck.fontVariations_[apiResponse.fonts[1].name], ['i7']);
83
-
90
+
84
91
  assertEquals(true, isSupport);
85
92
  };
86
93
 
@@ -90,17 +97,20 @@ FontdeckScriptTest.prototype.testNoProjectId = function() {
90
97
  };
91
98
  var insert = '';
92
99
  var src = '';
93
- var fakeDomHelper = {};
94
- var global = {};
95
- var fontdeck = new webfont.FontdeckScript(global, fakeDomHelper, configuration);
100
+ var fakeDomHelper = {
101
+ getLoadWindow: function() {
102
+ return {};
103
+ }
104
+ };
105
+ var fontdeck = new webfont.FontdeckScript(fakeDomHelper, configuration);
96
106
 
97
107
  // supportUserAgent
98
108
  var userAgent = 'user agent';
99
109
  var isSupport = null;
100
110
 
101
111
  fontdeck.supportUserAgent(userAgent, function(support) { isSupport = support; });
102
-
112
+
103
113
  assertEquals(fontdeck.fontFamilies_, []);
104
114
  assertEquals(fontdeck.fontVariations_, []);
105
115
  assertEquals(true, isSupport);
106
- }
116
+ }
@@ -2,7 +2,7 @@ var FontApiUrlBuilderTest = TestCase('FontApiUrlBuilderTest');
2
2
 
3
3
  FontApiUrlBuilderTest.prototype.testThrowsExceptionIfNoFontFamilies =
4
4
  function() {
5
- var fontApiUrlBuilder = new webfont.FontApiUrlBuilder("http://moo");
5
+ var fontApiUrlBuilder = new webfont.FontApiUrlBuilder("http://moo", "http:");
6
6
 
7
7
  try {
8
8
  fontApiUrlBuilder.build();
@@ -13,14 +13,14 @@ FontApiUrlBuilderTest.prototype.testThrowsExceptionIfNoFontFamilies =
13
13
  };
14
14
 
15
15
  FontApiUrlBuilderTest.prototype.testBuildProperUrl = function() {
16
- var fontApiUrlBuilder = new webfont.FontApiUrlBuilder("http://moo");
16
+ var fontApiUrlBuilder = new webfont.FontApiUrlBuilder("http://moo", "http:");
17
17
 
18
18
  fontApiUrlBuilder.setFontFamilies([ 'Font1', 'Font2' ]);
19
19
  assertEquals('http://moo?family=Font1%7CFont2', fontApiUrlBuilder.build());
20
20
  };
21
21
 
22
22
  FontApiUrlBuilderTest.prototype.testBuildProperDefaultUrl = function() {
23
- var fontApiUrlBuilder = new webfont.FontApiUrlBuilder();
23
+ var fontApiUrlBuilder = new webfont.FontApiUrlBuilder(undefined, "http:");
24
24
 
25
25
  fontApiUrlBuilder.setFontFamilies([ 'Font1', 'Font2' ]);
26
26
  assertEquals("http:" + webfont.FontApiUrlBuilder.DEFAULT_API_URL +
@@ -29,7 +29,7 @@ FontApiUrlBuilderTest.prototype.testBuildProperDefaultUrl = function() {
29
29
 
30
30
 
31
31
  FontApiUrlBuilderTest.prototype.testBuildProperUrlWithSubsets = function() {
32
- var fontApiUrlBuilder = new webfont.FontApiUrlBuilder();
32
+ var fontApiUrlBuilder = new webfont.FontApiUrlBuilder(undefined, "http:");
33
33
 
34
34
  fontApiUrlBuilder.setFontFamilies([ 'Font1:bold:greek,cyrillic',
35
35
  'Font2:italic', 'Font3' ]);
@@ -40,7 +40,7 @@ FontApiUrlBuilderTest.prototype.testBuildProperUrlWithSubsets = function() {
40
40
 
41
41
  FontApiUrlBuilderTest.prototype.testBuildProperUrlWithSubsetsNoVariations =
42
42
  function() {
43
- var fontApiUrlBuilder = new webfont.FontApiUrlBuilder();
43
+ var fontApiUrlBuilder = new webfont.FontApiUrlBuilder(undefined, "http:");
44
44
 
45
45
  fontApiUrlBuilder.setFontFamilies([ 'Font1:bold,italic:greek,cyrillic',
46
46
  'Font2:italic', 'Font3::latin' ]);
@@ -9,6 +9,9 @@ GoogleFontApiTest.prototype.testCallOnReadyWithFontFamilyLoading = function() {
9
9
  },
10
10
  createCssLink: function(csslink) {
11
11
  link = csslink;
12
+ },
13
+ getProtocol: function() {
14
+ return 'http:';
12
15
  }
13
16
  };
14
17
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
@@ -53,6 +56,9 @@ GoogleFontApiTest.prototype.testCallOnReadyWithFontFamilyLoadingApiUrlChanged =
53
56
  },
54
57
  createCssLink: function(csslink) {
55
58
  link = csslink;
59
+ },
60
+ getProtocol: function() {
61
+ return 'http:';
56
62
  }
57
63
  };
58
64
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
@@ -95,6 +101,9 @@ GoogleFontApiTest.prototype.testSpacesReplacedByPlus = function() {
95
101
  },
96
102
  createCssLink: function(csslink) {
97
103
  link = csslink;
104
+ },
105
+ getProtocol: function() {
106
+ return 'http:';
98
107
  }
99
108
  };
100
109
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
@@ -137,6 +146,9 @@ GoogleFontApiTest.prototype.testLoadWithVariations = function() {
137
146
  },
138
147
  createCssLink: function(csslink) {
139
148
  link = csslink;
149
+ },
150
+ getProtocol: function() {
151
+ return 'http:';
140
152
  }
141
153
  };
142
154
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
@@ -1,46 +1,7 @@
1
1
  var MonotypeScriptTest = TestCase('MonotypeScriptTest');
2
2
 
3
- MonotypeScriptTest.prototype.testIfProtocolMethodIsReturningProperly = function () {
4
- var fakeDocument = {
5
- location: { protocol: "https:" }
6
- };
7
- var global = {}; // should be window in actual situation.
8
- var script = null;
9
- var userAgent = new webfont.UserAgent("Test", "1.0", true);
10
- var config = { projectId: '01e2ff27-25bf-4801-a23e-73d328e6c7cc' };
11
- var fakedom = [];
12
- var fakeDomHelper = {
13
- createScriptSrc: function (s) {
14
- script = { src: s };
15
- return script;
16
- },
17
- insertInto: function (tag, elem) {
18
- fakedom[tag].push(elem);
19
- global[webfont.MonotypeScript.HOOK + config.projectId] = function () {
20
- return ["aachen bold", "kid print regualr"];
21
- };
22
- if (script.onload) {
23
- script.onload();
24
- }
25
- }
26
- };
27
-
28
- var monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocument, config);
29
- assertEquals("https:", monotypeScript.protocol());
30
-
31
- fakeDocument = {
32
- location: { protocol: "http:" }
33
- };
34
-
35
- monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocument, config);
36
- assertEquals("http:", monotypeScript.protocol());
37
- };
38
-
39
3
  MonotypeScriptTest.prototype.testIfScriptTagIsAdded = function () {
40
4
  var fakedom = { 'head': [], 'body': [] };
41
- var fakeDocument = {
42
- location: { protocol: "http:" }
43
- };
44
5
  var script = null;
45
6
  var global = {}; // should be window in actual situation.
46
7
  var families = null;
@@ -59,6 +20,12 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAdded = function () {
59
20
  if (script.onload) {
60
21
  script.onload();
61
22
  }
23
+ },
24
+ getLoadWindow: function () {
25
+ return global;
26
+ },
27
+ getProtocol: function () {
28
+ return "http:";
62
29
  }
63
30
  };
64
31
 
@@ -77,7 +44,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAdded = function () {
77
44
  }
78
45
  var isSupport = null;
79
46
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
80
- var monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocument, config);
47
+ var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config);
81
48
  monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; });
82
49
  monotypeScript.load(function (fontFamilies) {
83
50
  families = fontFamilies;
@@ -93,12 +60,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAdded = function () {
93
60
  //If current page is browsed using https protocol, the added script should be requested with SSL.
94
61
  MonotypeScriptTest.prototype.testIfScriptTagHasCorrectSSL = function () {
95
62
  var fakedom = { 'head': [], 'body': [] };
96
- var fakeDocument1 = {
97
- location: { protocol: "https:" }
98
- };
99
- var fakeDocument2 = {
100
- location: { protocol: "http:" }
101
- };
63
+ var fakeProtocol = "https:";
102
64
  var script = null;
103
65
  var global = {}; // should be window in actual situation.
104
66
  var families = null;
@@ -117,6 +79,12 @@ MonotypeScriptTest.prototype.testIfScriptTagHasCorrectSSL = function () {
117
79
  if (script.onload) {
118
80
  script.onload();
119
81
  }
82
+ },
83
+ getLoadWindow: function () {
84
+ return global;
85
+ },
86
+ getProtocol: function () {
87
+ return fakeProtocol;
120
88
  }
121
89
  };
122
90
 
@@ -136,7 +104,7 @@ MonotypeScriptTest.prototype.testIfScriptTagHasCorrectSSL = function () {
136
104
  }
137
105
  var isSupport = null;
138
106
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
139
- var monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocument1, config);
107
+ var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config);
140
108
  monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; });
141
109
  monotypeScript.load(function (fontFamilies) {
142
110
  families = fontFamilies;
@@ -150,7 +118,8 @@ MonotypeScriptTest.prototype.testIfScriptTagHasCorrectSSL = function () {
150
118
 
151
119
  //one page can have multiple projects, but not 2 projects with same projectId.
152
120
  config = { projectId: '01e2ff27-25bf-4801-a23e-73d328e6c7c1', api: "http://fast.fonts.com/jsapidev" };
153
- var monotypeScript2 = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocument2, config);
121
+ fakeProtocol = "http:";
122
+ var monotypeScript2 = new webfont.MonotypeScript(userAgent, fakeDomHelper, config);
154
123
  monotypeScript2.supportUserAgent(userAgent, function (support) { isSupport = support; });
155
124
  monotypeScript2.load(function (fontFamilies) {
156
125
  families = fontFamilies;
@@ -182,11 +151,11 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurl = function () {
182
151
  if (script.onload) {
183
152
  script.onload();
184
153
  }
185
- }
186
- };
187
-
188
- var fakeDocHelper = {
189
- protocol: function () {
154
+ },
155
+ getLoadWindow: function () {
156
+ return global;
157
+ },
158
+ getProtocol: function () {
190
159
  return "http:";
191
160
  }
192
161
  };
@@ -207,7 +176,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurl = function () {
207
176
 
208
177
  var isSupport = null;
209
178
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
210
- var monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocHelper, config);
179
+ var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config);
211
180
  monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; });
212
181
 
213
182
  monotypeScript.load(function (fontFamilies) {
@@ -224,7 +193,6 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurl = function () {
224
193
  //If current page is browsed using https protocol, the added script should be requested with SSL.
225
194
  MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurlAndTheScriptUrlHasCorrectSSL = function () {
226
195
  var fakedom = { 'head': [], 'body': [] };
227
- var fakeDocument = { location: { protocol: "https:"} };
228
196
  var global = {}; // should be window in actual situation.
229
197
  var script = null;
230
198
  var families = null;
@@ -243,6 +211,12 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurlAndTheScriptUrlH
243
211
  if (script.onload) {
244
212
  script.onload();
245
213
  }
214
+ },
215
+ getLoadWindow: function () {
216
+ return global;
217
+ },
218
+ getProtocol: function () {
219
+ return "https:";
246
220
  }
247
221
  };
248
222
 
@@ -262,7 +236,7 @@ MonotypeScriptTest.prototype.testIfScriptTagIsAddedWithoutApiurlAndTheScriptUrlH
262
236
 
263
237
  var isSupport = null;
264
238
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
265
- var monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocument, config);
239
+ var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config);
266
240
  monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; });
267
241
 
268
242
  monotypeScript.load(function (fontFamilies) {
@@ -297,18 +271,18 @@ MonotypeScriptTest.prototype.testWithoutProjectId = function () {
297
271
  if (script.onload) {
298
272
  script.onload();
299
273
  }
300
- }
301
- };
302
-
303
- var fakeDocHelper = {
304
- protocol: function () {
274
+ },
275
+ getLoadWindow: function () {
276
+ return global;
277
+ },
278
+ getProtocol: function () {
305
279
  return "http:";
306
280
  }
307
281
  };
308
282
 
309
283
  var isSupport = null;
310
284
  var userAgent = new webfont.UserAgent("Test", "1.0", true);
311
- var monotypeScript = new webfont.MonotypeScript(global, userAgent, fakeDomHelper, fakeDocHelper, config);
285
+ var monotypeScript = new webfont.MonotypeScript(userAgent, fakeDomHelper, config);
312
286
  monotypeScript.supportUserAgent(userAgent, function (support) { isSupport = support; });
313
287
 
314
288
  monotypeScript.load(function (fontFamilies) {
@@ -6,16 +6,22 @@ TypekitScriptTest.prototype.testSupportAndLoadLifecycle = function() {
6
6
  };
7
7
  var insert = '';
8
8
  var src = '';
9
+ var global = {};
9
10
  var fakeDomHelper = {
10
11
  insertInto: function(tag, e) {
11
12
  insert = tag;
12
13
  },
13
14
  createScriptSrc: function(srcLink) {
14
15
  src = srcLink;
16
+ },
17
+ getLoadWindow: function() {
18
+ return global;
19
+ },
20
+ getProtocol: function() {
21
+ return 'http:';
15
22
  }
16
23
  };
17
- var global = {};
18
- var typeKit = new webfont.TypekitScript(global, fakeDomHelper, configuration);
24
+ var typeKit = new webfont.TypekitScript(fakeDomHelper, configuration);
19
25
 
20
26
  // supportUserAgent
21
27
  var userAgent = 'user agent';
@@ -65,16 +71,22 @@ TypekitScriptTest.prototype.testLoadWithVariations = function() {
65
71
  };
66
72
  var insert = '';
67
73
  var src = '';
74
+ var global = {};
68
75
  var fakeDomHelper = {
69
76
  insertInto: function(tag, e) {
70
77
  insert = tag;
71
78
  },
72
79
  createScriptSrc: function(srcLink) {
73
80
  src = srcLink;
81
+ },
82
+ getLoadWindow: function() {
83
+ return global;
84
+ },
85
+ getProtocol: function() {
86
+ return 'http:';
74
87
  }
75
88
  };
76
- var global = {};
77
- var typeKit = new webfont.TypekitScript(global, fakeDomHelper, configuration);
89
+ var typeKit = new webfont.TypekitScript(fakeDomHelper, configuration);
78
90
 
79
91
  // supportUserAgent
80
92
  var userAgent = 'user agent';
@@ -129,9 +141,15 @@ TypekitScriptTest.prototype.testAlternateApi = function() {
129
141
  },
130
142
  createScriptSrc: function(srcLink) {
131
143
  src = srcLink;
144
+ },
145
+ getLoadWindow: function() {
146
+ return {};
147
+ },
148
+ getProtocol: function() {
149
+ return 'http:';
132
150
  }
133
151
  };
134
- var typeKit = new webfont.TypekitScript({}, fakeDomHelper, configuration);
152
+ var typeKit = new webfont.TypekitScript(fakeDomHelper, configuration);
135
153
  var userAgent = 'user agent';
136
154
  var isSupport = null;
137
155
 
@@ -152,9 +170,15 @@ TypekitScriptTest.prototype.testNoKitId = function() {
152
170
  },
153
171
  createScriptSrc: function(srcLink) {
154
172
  src = srcLink;
173
+ },
174
+ getLoadWindow: function() {
175
+ return {};
176
+ },
177
+ getProtocol: function() {
178
+ return 'http:';
155
179
  }
156
180
  };
157
- var typeKit = new webfont.TypekitScript({}, fakeDomHelper, configuration);
181
+ var typeKit = new webfont.TypekitScript(fakeDomHelper, configuration);
158
182
  var userAgent = 'user agent';
159
183
  var isSupport = null;
160
184
 
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'webfontloader'
16
- s.version = '1.0.31'
17
- s.date = '2012-09-11'
16
+ s.version = '1.1.0'
17
+ s.date = '2012-12-05'
18
18
 
19
19
  ## Make sure your summary is short. The description may be as long
20
20
  ## as you like.
@@ -75,8 +75,11 @@ DESC
75
75
  docs/MODULES.md
76
76
  docs/TRANSITIONS.md
77
77
  lib/webfontloader.rb
78
+ lib/webfontloader/demo/public/ascender-iframe.html
78
79
  lib/webfontloader/demo/public/ascender.html
79
80
  lib/webfontloader/demo/public/basic.css
81
+ lib/webfontloader/demo/public/blank.html
82
+ lib/webfontloader/demo/public/custom-iframe.html
80
83
  lib/webfontloader/demo/public/custom.html
81
84
  lib/webfontloader/demo/public/event-css-active-multiple.html
82
85
  lib/webfontloader/demo/public/event-css-active.html
@@ -90,13 +93,16 @@ DESC
90
93
  lib/webfontloader/demo/public/fontdeck.html
91
94
  lib/webfontloader/demo/public/fontwatchrunner-default-fonts.html
92
95
  lib/webfontloader/demo/public/google-css.html
96
+ lib/webfontloader/demo/public/google-iframe.html
93
97
  lib/webfontloader/demo/public/google.html
94
98
  lib/webfontloader/demo/public/ie-fast-js.html
95
99
  lib/webfontloader/demo/public/ie-slow-js.html
96
100
  lib/webfontloader/demo/public/ie-slow-link.html
97
101
  lib/webfontloader/demo/public/index.html
98
102
  lib/webfontloader/demo/public/jquery.min.js
103
+ lib/webfontloader/demo/public/monotype-iframe.html
99
104
  lib/webfontloader/demo/public/monotype.html
105
+ lib/webfontloader/demo/public/typekit-iframe.html
100
106
  lib/webfontloader/demo/public/typekit-variations.html
101
107
  lib/webfontloader/demo/public/typekit.html
102
108
  lib/webfontloader/demo/server.rb