sproutcore 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 (270) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +269 -0
  4. data/README.txt +67 -0
  5. data/Rakefile +4 -0
  6. data/app_generators/sproutcore/USAGE +5 -0
  7. data/app_generators/sproutcore/sproutcore_generator.rb +66 -0
  8. data/app_generators/sproutcore/templates/README +77 -0
  9. data/app_generators/sproutcore/templates/environment.yml +4 -0
  10. data/bin/sc-build +145 -0
  11. data/bin/sc-gen +24 -0
  12. data/bin/sc-server +63 -0
  13. data/bin/sproutcore +21 -0
  14. data/clients/sc_docs/controllers/docs.js +118 -0
  15. data/clients/sc_docs/core.js +19 -0
  16. data/clients/sc_docs/english.lproj/body.css +159 -0
  17. data/clients/sc_docs/english.lproj/body.rhtml +33 -0
  18. data/clients/sc_docs/english.lproj/controls.css +0 -0
  19. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  20. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  21. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  22. data/clients/sc_docs/english.lproj/images/indicator.gif +0 -0
  23. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  24. data/clients/sc_docs/english.lproj/no_docs.rhtml +7 -0
  25. data/clients/sc_docs/english.lproj/strings.js +14 -0
  26. data/clients/sc_docs/english.lproj/warning.rhtml +6 -0
  27. data/clients/sc_docs/fixtures/doc.js +11 -0
  28. data/clients/sc_docs/main.js +21 -0
  29. data/clients/sc_docs/models/doc.js +9 -0
  30. data/clients/sc_docs/tests/controllers/docs.rhtml +21 -0
  31. data/clients/sc_docs/tests/models/doc.rhtml +21 -0
  32. data/clients/sc_docs/tests/views/doc_frame.rhtml +21 -0
  33. data/clients/sc_docs/tests/views/doc_label_view.rhtml +21 -0
  34. data/clients/sc_docs/views/doc_frame.js +33 -0
  35. data/clients/sc_docs/views/doc_label.js +20 -0
  36. data/clients/sc_test_runner/controllers/runner.js +175 -0
  37. data/clients/sc_test_runner/core.js +19 -0
  38. data/clients/sc_test_runner/english.lproj/body.css +151 -0
  39. data/clients/sc_test_runner/english.lproj/body.rhtml +35 -0
  40. data/clients/sc_test_runner/english.lproj/controls.css +0 -0
  41. data/clients/sc_test_runner/english.lproj/icons/small/next.png +0 -0
  42. data/clients/sc_test_runner/english.lproj/icons/small/reset.png +0 -0
  43. data/clients/sc_test_runner/english.lproj/images/gradients.png +0 -0
  44. data/clients/sc_test_runner/english.lproj/images/indicator.gif +0 -0
  45. data/clients/sc_test_runner/english.lproj/images/toolbar.png +0 -0
  46. data/clients/sc_test_runner/english.lproj/no_tests.rhtml +6 -0
  47. data/clients/sc_test_runner/english.lproj/strings.js +14 -0
  48. data/clients/sc_test_runner/english.lproj/warning.rhtml +6 -0
  49. data/clients/sc_test_runner/fixtures/test.js +12 -0
  50. data/clients/sc_test_runner/main.js +26 -0
  51. data/clients/sc_test_runner/models/test.js +11 -0
  52. data/clients/sc_test_runner/views/runner_frame.js +72 -0
  53. data/clients/sc_test_runner/views/test_label.js +20 -0
  54. data/config/hoe.rb +70 -0
  55. data/config/requirements.rb +17 -0
  56. data/environment.yml +9 -0
  57. data/frameworks/prototype/prototype.js +4186 -0
  58. data/frameworks/sproutcore/Core.js +378 -0
  59. data/frameworks/sproutcore/README +3 -0
  60. data/frameworks/sproutcore/controllers/array.js +236 -0
  61. data/frameworks/sproutcore/controllers/collection.js +305 -0
  62. data/frameworks/sproutcore/controllers/controller.js +323 -0
  63. data/frameworks/sproutcore/controllers/object.js +372 -0
  64. data/frameworks/sproutcore/drag/drag.js +549 -0
  65. data/frameworks/sproutcore/drag/drag_data_source.js +32 -0
  66. data/frameworks/sproutcore/drag/drag_source.js +64 -0
  67. data/frameworks/sproutcore/drag/drop_target.js +153 -0
  68. data/frameworks/sproutcore/english.lproj/blank.gif +0 -0
  69. data/frameworks/sproutcore/english.lproj/buttons.css +589 -0
  70. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  71. data/frameworks/sproutcore/english.lproj/inline_text_editor.css +21 -0
  72. data/frameworks/sproutcore/english.lproj/menu.css +121 -0
  73. data/frameworks/sproutcore/english.lproj/panels/background-fat.jpg +0 -0
  74. data/frameworks/sproutcore/english.lproj/panels/background-thin.jpg +0 -0
  75. data/frameworks/sproutcore/english.lproj/panels/bottom-edge.png +0 -0
  76. data/frameworks/sproutcore/english.lproj/panels/bottom-left-corner.png +0 -0
  77. data/frameworks/sproutcore/english.lproj/panels/bottom-right-corner.png +0 -0
  78. data/frameworks/sproutcore/english.lproj/panels/left-edge.png +0 -0
  79. data/frameworks/sproutcore/english.lproj/panels/overlay.png +0 -0
  80. data/frameworks/sproutcore/english.lproj/panels/right-edge.png +0 -0
  81. data/frameworks/sproutcore/english.lproj/panels/top-edge.png +0 -0
  82. data/frameworks/sproutcore/english.lproj/panels/top-left-corner.png +0 -0
  83. data/frameworks/sproutcore/english.lproj/panels/top-right-corner.png +0 -0
  84. data/frameworks/sproutcore/english.lproj/panes.css +155 -0
  85. data/frameworks/sproutcore/english.lproj/picker.css +22 -0
  86. data/frameworks/sproutcore/english.lproj/strings.js +15 -0
  87. data/frameworks/sproutcore/english.lproj/tab.css +23 -0
  88. data/frameworks/sproutcore/english.lproj/tests.css +67 -0
  89. data/frameworks/sproutcore/english.lproj/theme.css +77 -0
  90. data/frameworks/sproutcore/foundation/animator.js +670 -0
  91. data/frameworks/sproutcore/foundation/application.js +199 -0
  92. data/frameworks/sproutcore/foundation/array.js +348 -0
  93. data/frameworks/sproutcore/foundation/benchmark.js +211 -0
  94. data/frameworks/sproutcore/foundation/binding.js +384 -0
  95. data/frameworks/sproutcore/foundation/date.js +357 -0
  96. data/frameworks/sproutcore/foundation/error.js +39 -0
  97. data/frameworks/sproutcore/foundation/input_manager.js +153 -0
  98. data/frameworks/sproutcore/foundation/json.js +296 -0
  99. data/frameworks/sproutcore/foundation/mock.js +42 -0
  100. data/frameworks/sproutcore/foundation/node_descriptor.js +56 -0
  101. data/frameworks/sproutcore/foundation/object.js +777 -0
  102. data/frameworks/sproutcore/foundation/observable.js +451 -0
  103. data/frameworks/sproutcore/foundation/page.js +63 -0
  104. data/frameworks/sproutcore/foundation/path_module.js +413 -0
  105. data/frameworks/sproutcore/foundation/responder.js +310 -0
  106. data/frameworks/sproutcore/foundation/routes.js +371 -0
  107. data/frameworks/sproutcore/foundation/run_loop.js +21 -0
  108. data/frameworks/sproutcore/foundation/server.js +491 -0
  109. data/frameworks/sproutcore/foundation/set.js +96 -0
  110. data/frameworks/sproutcore/foundation/string.js +149 -0
  111. data/frameworks/sproutcore/foundation/undo_manager.js +186 -0
  112. data/frameworks/sproutcore/foundation/unittest.js +622 -0
  113. data/frameworks/sproutcore/foundation/utils.js +61 -0
  114. data/frameworks/sproutcore/globals/panels.js +182 -0
  115. data/frameworks/sproutcore/globals/popups.js +60 -0
  116. data/frameworks/sproutcore/globals/window.js +381 -0
  117. data/frameworks/sproutcore/lib/index.rhtml +66 -0
  118. data/frameworks/sproutcore/models/collection.js +395 -0
  119. data/frameworks/sproutcore/models/record.js +622 -0
  120. data/frameworks/sproutcore/models/store.js +295 -0
  121. data/frameworks/sproutcore/panes/dialog.js +16 -0
  122. data/frameworks/sproutcore/panes/manager.js +164 -0
  123. data/frameworks/sproutcore/panes/menu.js +45 -0
  124. data/frameworks/sproutcore/panes/overlay.js +231 -0
  125. data/frameworks/sproutcore/panes/pane.js +90 -0
  126. data/frameworks/sproutcore/panes/panel.js +19 -0
  127. data/frameworks/sproutcore/panes/picker.js +45 -0
  128. data/frameworks/sproutcore/tests/controllers/array.rhtml +86 -0
  129. data/frameworks/sproutcore/tests/controllers/controller.rhtml +273 -0
  130. data/frameworks/sproutcore/tests/controllers/object.rhtml +327 -0
  131. data/frameworks/sproutcore/tests/foundation/application.rhtml +125 -0
  132. data/frameworks/sproutcore/tests/foundation/array.rhtml +221 -0
  133. data/frameworks/sproutcore/tests/foundation/object.rhtml +69 -0
  134. data/frameworks/sproutcore/tests/globals/window.rhtml +45 -0
  135. data/frameworks/sproutcore/tests/panes/pane.rhtml +88 -0
  136. data/frameworks/sproutcore/tests/views/collection.rhtml +137 -0
  137. data/frameworks/sproutcore/tests/views/popup_button.rhtml +115 -0
  138. data/frameworks/sproutcore/tests/views/text_field.rhtml +37 -0
  139. data/frameworks/sproutcore/validators/credit_card.js +92 -0
  140. data/frameworks/sproutcore/validators/date.js +36 -0
  141. data/frameworks/sproutcore/validators/email.js +29 -0
  142. data/frameworks/sproutcore/validators/not_empty.js +24 -0
  143. data/frameworks/sproutcore/validators/number.js +55 -0
  144. data/frameworks/sproutcore/validators/password.js +78 -0
  145. data/frameworks/sproutcore/validators/validator.js +304 -0
  146. data/frameworks/sproutcore/views/button.js +425 -0
  147. data/frameworks/sproutcore/views/checkbox_field.js +30 -0
  148. data/frameworks/sproutcore/views/collection.js +1521 -0
  149. data/frameworks/sproutcore/views/container.js +62 -0
  150. data/frameworks/sproutcore/views/error_explanation.js +45 -0
  151. data/frameworks/sproutcore/views/field.js +214 -0
  152. data/frameworks/sproutcore/views/filter_button.js +29 -0
  153. data/frameworks/sproutcore/views/form.js +591 -0
  154. data/frameworks/sproutcore/views/image.js +141 -0
  155. data/frameworks/sproutcore/views/inline_text_editor.js +96 -0
  156. data/frameworks/sproutcore/views/label.js +176 -0
  157. data/frameworks/sproutcore/views/menu_item.js +90 -0
  158. data/frameworks/sproutcore/views/pagination.js +54 -0
  159. data/frameworks/sproutcore/views/popup_button.js +86 -0
  160. data/frameworks/sproutcore/views/popup_menu.js +137 -0
  161. data/frameworks/sproutcore/views/progress.js +100 -0
  162. data/frameworks/sproutcore/views/radio_field.js +107 -0
  163. data/frameworks/sproutcore/views/radio_group.js +48 -0
  164. data/frameworks/sproutcore/views/segmented.js +80 -0
  165. data/frameworks/sproutcore/views/select_field.js +272 -0
  166. data/frameworks/sproutcore/views/spinner.js +11 -0
  167. data/frameworks/sproutcore/views/tab.js +126 -0
  168. data/frameworks/sproutcore/views/text_field.js +179 -0
  169. data/frameworks/sproutcore/views/textarea_field.js +14 -0
  170. data/frameworks/sproutcore/views/toolbar.js +29 -0
  171. data/frameworks/sproutcore/views/view.js +1389 -0
  172. data/frameworks/sproutcore/views/workspace.js +170 -0
  173. data/generators/client/README +3 -0
  174. data/generators/client/USAGE +12 -0
  175. data/generators/client/client_generator.rb +53 -0
  176. data/generators/client/templates/core.js +19 -0
  177. data/generators/client/templates/english.lproj/body.css +0 -0
  178. data/generators/client/templates/english.lproj/body.rhtml +3 -0
  179. data/generators/client/templates/english.lproj/controls.css +0 -0
  180. data/generators/client/templates/english.lproj/strings.js +14 -0
  181. data/generators/client/templates/main.js +37 -0
  182. data/generators/controller/USAGE +16 -0
  183. data/generators/controller/controller_generator.rb +51 -0
  184. data/generators/controller/templates/controller.js +21 -0
  185. data/generators/controller/templates/test.rhtml +21 -0
  186. data/generators/framework/README +7 -0
  187. data/generators/framework/USAGE +12 -0
  188. data/generators/framework/framework_generator.rb +53 -0
  189. data/generators/framework/templates/core.js +20 -0
  190. data/generators/framework/templates/english.lproj/body.css +0 -0
  191. data/generators/framework/templates/english.lproj/body.rhtml +3 -0
  192. data/generators/framework/templates/english.lproj/controls.css +0 -0
  193. data/generators/framework/templates/english.lproj/strings.js +14 -0
  194. data/generators/language/USAGE +16 -0
  195. data/generators/language/language_generator.rb +47 -0
  196. data/generators/language/templates/strings.js +10 -0
  197. data/generators/model/USAGE +24 -0
  198. data/generators/model/model_generator.rb +55 -0
  199. data/generators/model/templates/fixture.js +11 -0
  200. data/generators/model/templates/model.js +20 -0
  201. data/generators/model/templates/test.rhtml +21 -0
  202. data/generators/test/USAGE +16 -0
  203. data/generators/test/templates/test.rhtml +21 -0
  204. data/generators/test/test_generator.rb +47 -0
  205. data/generators/view/USAGE +16 -0
  206. data/generators/view/templates/test.rhtml +21 -0
  207. data/generators/view/templates/view.js +20 -0
  208. data/generators/view/view_generator.rb +51 -0
  209. data/jsdoc/README.txt +119 -0
  210. data/jsdoc/app/DocFile.js +137 -0
  211. data/jsdoc/app/DocTag.js +110 -0
  212. data/jsdoc/app/Doclet.js +63 -0
  213. data/jsdoc/app/Dumper.js +143 -0
  214. data/jsdoc/app/JsDoc.js +103 -0
  215. data/jsdoc/app/JsHilite.js +45 -0
  216. data/jsdoc/app/JsIO.js +163 -0
  217. data/jsdoc/app/JsParse.js +385 -0
  218. data/jsdoc/app/JsPlate.js +130 -0
  219. data/jsdoc/app/JsTestrun.js +129 -0
  220. data/jsdoc/app/JsToke.js +564 -0
  221. data/jsdoc/app/Symbol.js +298 -0
  222. data/jsdoc/app/Transformer.js +14 -0
  223. data/jsdoc/app/Util.js +97 -0
  224. data/jsdoc/app/js.jar +0 -0
  225. data/jsdoc/app/run.js +144 -0
  226. data/jsdoc/plugins/min.js +316 -0
  227. data/jsdoc/plugins/strip.js +20 -0
  228. data/jsdoc/templates/sproutcore/class.tmpl +438 -0
  229. data/jsdoc/templates/sproutcore/default.css +241 -0
  230. data/jsdoc/templates/sproutcore/index.html +13 -0
  231. data/jsdoc/templates/sproutcore/index.tmpl +21 -0
  232. data/jsdoc/templates/sproutcore/prototype.js +4186 -0
  233. data/jsdoc/templates/sproutcore/publish.js +236 -0
  234. data/jsdoc/templates/sproutcore/splash.html +7 -0
  235. data/lib/sproutcore/build_tools/html_builder.rb +88 -0
  236. data/lib/sproutcore/build_tools/resource_builder.rb +194 -0
  237. data/lib/sproutcore/build_tools.rb +44 -0
  238. data/lib/sproutcore/bundle.rb +517 -0
  239. data/lib/sproutcore/bundle_manifest.rb +397 -0
  240. data/lib/sproutcore/generator_helper.rb +170 -0
  241. data/lib/sproutcore/helpers/capture_helper.rb +42 -0
  242. data/lib/sproutcore/helpers/static_helper.rb +80 -0
  243. data/lib/sproutcore/helpers/tag_helper.rb +110 -0
  244. data/lib/sproutcore/helpers/text_helper.rb +336 -0
  245. data/lib/sproutcore/helpers.rb +3 -0
  246. data/lib/sproutcore/jsdoc.rb +40 -0
  247. data/lib/sproutcore/jsmin.rb +247 -0
  248. data/lib/sproutcore/library.rb +258 -0
  249. data/lib/sproutcore/merb/bundle_controller.rb +179 -0
  250. data/lib/sproutcore/merb/router.rb +43 -0
  251. data/lib/sproutcore/merb.rb +27 -0
  252. data/lib/sproutcore/version.rb +9 -0
  253. data/lib/sproutcore/view_helpers/button_views.rb +302 -0
  254. data/lib/sproutcore/view_helpers/core_views.rb +284 -0
  255. data/lib/sproutcore/view_helpers/form_views.rb +258 -0
  256. data/lib/sproutcore/view_helpers/menu_views.rb +94 -0
  257. data/lib/sproutcore/view_helpers.rb +628 -0
  258. data/lib/sproutcore.rb +30 -0
  259. data/script/destroy +14 -0
  260. data/script/generate +14 -0
  261. data/script/txt2html +74 -0
  262. data/setup.rb +1585 -0
  263. data/spec/spec.opts +1 -0
  264. data/spec/spec_helper.rb +7 -0
  265. data/spec/sproutcore_spec.rb +11 -0
  266. data/tasks/deployment.rake +34 -0
  267. data/tasks/environment.rake +7 -0
  268. data/tasks/rspec.rake +21 -0
  269. data/tasks/website.rake +17 -0
  270. metadata +365 -0
@@ -0,0 +1,397 @@
1
+ require 'yaml'
2
+
3
+ module SproutCore
4
+
5
+ # A Bundle Manifest describes all of the resources in a bundle, including mapping their
6
+ # source paths, destination paths, and urls.
7
+ #
8
+ # A Bundle will create a manifest for every language you request from it. If you invoke
9
+ # reload! on the bundle, it will dispose of its manifests and rebuild them.
10
+ #
11
+ class BundleManifest
12
+
13
+ CACHED_TYPES = [:javascript, :stylesheet, :fixture, :test]
14
+ SYMLINKED_TYPES = [:resource]
15
+
16
+ attr_reader :bundle, :language
17
+
18
+ def initialize(bundle, language)
19
+ @bundle = bundle
20
+ @language = language
21
+ @entries_by_type = {} # entries by type
22
+ @entries_by_filename = {} # entries by files
23
+ build!
24
+ end
25
+
26
+ # ==== Returns
27
+ # All entries as an array
28
+ #
29
+ def entries; @entries_by_filename.values; end
30
+
31
+ # ==== Returns
32
+ # All of the entries matching the specified type
33
+ #
34
+ def entries_for(resource_type)
35
+ @entries_by_type[resource_type] || []
36
+ end
37
+
38
+ # ==== Returns
39
+ # Entry for the resource with the specified name
40
+ #
41
+ def entry_for(resource_name)
42
+ @entries_by_filename[resource_name] || nil
43
+ end
44
+
45
+ def to_a; @entries_by_filename.values.map { |x| x.to_hash }; end
46
+ def to_hash; @entries_by_type; end
47
+ def to_s; @entries_by_filename.to_yaml; end
48
+
49
+ protected
50
+
51
+ # Builds a manifest for the bundle and the specified language
52
+ def build!
53
+
54
+ # STEP 1: Catalog all of the files in the project, including the target language
55
+ # and the default language. This will filter out resources not used in this language.
56
+ entries = catalog_entries
57
+
58
+ # STEP 2: Combine the HTML file paths into a single entry, unless this is a framework
59
+ if (working = entries[:html]) && working.size > 0
60
+ if bundle.can_have_html?
61
+ working << build_entry_for('index.html', :html, working)
62
+ else
63
+ working.each { |x| x.hidden = true }
64
+ end
65
+ end
66
+
67
+ # STEP 3: If in development build mode:
68
+ if bundle.build_mode == :development
69
+
70
+ # a. Merge fixture types into JS types & tests
71
+ unless entries[:fixture].nil?
72
+ entries[:javascript] = (entries[:javascript] || []) + entries[:fixture]
73
+ end
74
+
75
+ # b. Rewrite all of the JS & CSS file paths and URLs to point to cached versions
76
+ # (Cached versions are written to _cache/filename-ctime.ext)
77
+ (entries[:javascript] ||= []).each do | entry |
78
+ setup_timestamp_token(entry)
79
+ end
80
+
81
+ (entries[:stylesheet] ||= []).each do | entry |
82
+ setup_timestamp_token(entry)
83
+ end
84
+
85
+ # c. Rewrite the URLs for all other resources to go through the _src symlink
86
+ ##-----> Already done build_entry_for()
87
+
88
+
89
+ # STEP 4: If in production mode, remove extra assets that should never be built
90
+ else
91
+
92
+ # c. Remove the entries for anything that is not JS, CSS, HTML or Resource
93
+ entries.delete(:fixture)
94
+ entries.delete(:test)
95
+ end
96
+
97
+ # STEP 5: Add entry for javascript.js & stylesheet.js. If in production mode, set
98
+ # these to visible and hide the composite. If in dev mode, do the opposite.
99
+
100
+ hide_composite = (bundle.build_mode != :development)
101
+
102
+ # a. Combine the JS file paths into a single entry for the javascript.js
103
+ if (working = entries[:javascript]) && working.size>0
104
+ entry = build_entry_for('javascript.js', :javascript, working, hide_composite)
105
+ entry.hidden = true unless hide_composite
106
+ working << entry
107
+ end
108
+
109
+ # b. Combine the CSS file paths into a single entry for the stylesheet.css
110
+ if (working = entries[:stylesheet]) && working.size>0
111
+ entry = build_entry_for('stylesheet.css', :stylesheet, working, hide_composite)
112
+ entry.hidden = true unless hide_composite
113
+ working << entry
114
+ end
115
+
116
+ # Save entries into hashes
117
+ @entries_by_type = entries
118
+ @entries_by_filenames = {}
119
+ entries.values.flatten.each { |entry| @entries_by_filename[entry.filename] = entry }
120
+ end
121
+
122
+ # Build a catalog of entries for this manifest. This will simply filter out the files
123
+ # that don't actually belong in the current language
124
+ def catalog_entries
125
+
126
+ # Entries arranged by resource filename
127
+ entries = {}
128
+ default_lproj_entries = {}
129
+ target_lproj_entries = {}
130
+
131
+ # Get the name of the lproj dirs for the default and current languages
132
+ default_lproj = bundle.lproj_for(bundle.preferred_language)
133
+ target_lproj = bundle.lproj_for(language)
134
+
135
+ # Any files living in the two lproj dirs will be shunted off into these arrays
136
+ # and processed later to make sure we process them in the right order
137
+ default_lproj_files = []
138
+ target_lproj_files = []
139
+
140
+ # Now, glob all the files and sort through them
141
+ old_wd = Dir.getwd; Dir.chdir(bundle.source_root)
142
+ Dir.glob(File.join('**','*')).each do | src_path |
143
+
144
+ # Get source type. Skip any without a useful type
145
+ next if (src_type = type_of(src_path)) == :skip
146
+
147
+ # Get current lproj (if there is one). Skip if not default or current
148
+ if current_lproj = src_path.match(/^([^\/]+\.lproj)\//).to_a[1]
149
+ next if (current_lproj != default_lproj) && (current_lproj != target_lproj)
150
+ end
151
+
152
+ # OK, pass all of our validations. Go ahead and build an entry for this
153
+ # Add entry to list of entries for appropriate lproj if localized
154
+ entry = build_entry_for(src_path, src_type)
155
+ case current_lproj
156
+ when default_lproj
157
+ default_lproj_entries[entry.filename] = entry
158
+ when target_lproj
159
+ target_lproj_entries[entry.filename] = entry
160
+ else
161
+ entries[entry.filename] = entry
162
+ end
163
+ end
164
+ Dir.chdir(old_wd) # restore wd
165
+
166
+ # Now, new in default and target lproj entries. This will overwrite entries that exist
167
+ # in both places.
168
+ entries.merge!(default_lproj_entries)
169
+ entries.merge!(target_lproj_entries)
170
+
171
+ # Finally, entries will need to be grouped by type to allow further processing.
172
+ ret = {}
173
+ entries.values.each { |entry| (ret[entry.type] ||= []) << entry }
174
+ return ret
175
+ end
176
+
177
+ # Determines the type for this manifest entry. Should be one of:
178
+ #
179
+ # stylesheet:: a CSS file
180
+ # javascript:: a JavaScript file
181
+ # html:: an HTML file
182
+ #
183
+ # test:: a test file (inside of /tests)
184
+ # fixture:: a fixture file (inside of /fixtures)
185
+ #
186
+ # resource:: any other file inside an lproj dir
187
+ # skip:: any other file outside of an lproj dir directories
188
+ #
189
+ # If you need to handle additional types of resources in the future, this is the place to
190
+ # put it.
191
+ #
192
+ # ==== Params
193
+ #
194
+ # src_path:: The source path, relative to source_root.
195
+ #
196
+ def type_of(src_path)
197
+ return :skip if File.directory?(src_path)
198
+ case src_path
199
+ when /^tests\/.+/
200
+ :test
201
+ when /^fixtures\/.+/
202
+ :fixture
203
+ when /.html$/
204
+ :html
205
+ when /.rhtml$/
206
+ :html
207
+ when /.html.erb$/
208
+ :html
209
+ when /.css$/
210
+ :stylesheet
211
+ when /.js$/
212
+ :javascript
213
+ when /\.lproj\/.+/
214
+ :resource
215
+ else
216
+ :skip
217
+ end
218
+ end
219
+
220
+ # Build an entry for the resource at the named src_path (relative to the source_root)
221
+ # This should assume we are in going to simply build each resource into the build root
222
+ # without combining files, but not using our _src symlink magic.
223
+ def build_entry_for(src_path, src_type, composite=nil, hide_composite = true)
224
+ ret = ManifestEntry.new
225
+ ret.ext = File.extname(src_path)[1..-1] || '' # easy stuff
226
+ ret.type = src_type
227
+ ret.original_path = src_path
228
+ ret.hidden = false
229
+ ret.language = language
230
+
231
+ # the filename is the src_path less any lproj in the front
232
+ ret.filename = src_path.gsub(/^[^\/]+.lproj\//,'')
233
+
234
+ # the source path is just the combine source root + the path
235
+ ret.source_path = (composite.nil?) ? File.join(bundle.source_root, src_path) : nil
236
+
237
+ # set the composite property. The passed in array should contain other entries
238
+ # if hide_composite is true, then hide the composite items as well
239
+ unless composite.nil? || composite.size == 0
240
+ composite.each { |x| x.hidden = true } if hide_composite
241
+ ret.composite = composite.map { |x| x.filename }
242
+ end
243
+
244
+ # The build path is the build_root + the filename
245
+ # The URL is the url root + the language code + filename
246
+ # also add in _cache or _sym in certain cases. This is just more efficient than doing
247
+ # it later.
248
+ url_root = (src_path == 'index.html') ? bundle.index_root : bundle.url_root
249
+ cache_link = nil
250
+ use_symlink =false
251
+
252
+ # Note: you can only access real resources via the cache. If the entry is a composite
253
+ # then do not go through cache.
254
+ if (bundle.build_mode == :development) && composite.nil?
255
+ cache_link = '_cache' if CACHED_TYPES.include?(src_type)
256
+ use_symlink = true if SYMLINKED_TYPES.include?(src_type)
257
+ end
258
+
259
+ ret.use_symlink = use_symlink
260
+ if use_symlink
261
+ ret.build_path = File.join(bundle.build_root, '_src', src_path)
262
+ ret.url = [url_root, '_src', src_path].join('/')
263
+ else
264
+ ret.build_path = File.join(*[bundle.build_root, language.to_s, cache_link, ret.filename].compact)
265
+ ret.url = [url_root, language.to_s, cache_link, ret.filename].compact.join('/')
266
+ end
267
+
268
+ # Done.
269
+ return ret
270
+ end
271
+
272
+ # Lookup the timestamp on the source path and interpolate that into the filename URL.
273
+ # also insert the _cache element.
274
+ def setup_timestamp_token(entry)
275
+ timestamp = entry.timestamp
276
+ extname = File.extname(entry.url)
277
+ entry.url = entry.url.gsub(/#{extname}$/,"-#{timestamp}#{extname}") # add timestamp
278
+
279
+ extname = File.extname(entry.build_path)
280
+ entry.build_path = entry.build_path.gsub(/#{extname}$/,"-#{timestamp}#{extname}") # add timestamp
281
+
282
+ puts "\n\n*setup_timestamp_token(#{entry.url} - #{entry.timestamp})" if /docs-/ =~ entry.url
283
+ end
284
+ end
285
+
286
+ # describes a single entry in the Manifest:
287
+ #
288
+ # filename:: path relative to the built language (e.g. sproutcore/en) less file extension
289
+ # ext:: the file extension
290
+ # source_path:: absolute paths into source that will comprise this resource
291
+ # url:: the url that should be used to reference this resource
292
+ # build_path:: absolute path to the compiled resource
293
+ # type:: the top-level category
294
+ # original_path:: save the original path used to build this entry
295
+ # hidden:: if true, this entry is needed internally, but otherwise should not be used
296
+ # use_symlink:: if true, then this entry should be handled via the build symlink
297
+ # language:: the language in use when this entry was created
298
+ # composite:: If set, this will contain the filenames of other resources that should be
299
+ # combined to form this resource.
300
+ #
301
+ class ManifestEntry < Struct.new(:filename, :ext, :source_path, :url, :build_path, :type, :original_path, :hidden, :use_symlink, :language, :composite)
302
+ def to_hash
303
+ ret = {}
304
+ self.members.zip(self.values).each { |p| ret[p[0]] = p[1] }
305
+ ret.symbolize_keys
306
+ end
307
+
308
+ def hidden?; !!hidden; end
309
+ def use_symlink?; !!use_symlink; end
310
+ def composite?; !!composite; end
311
+
312
+ # Returns true if this entry can be cached even in development mode. Composite resources
313
+ # and tests need to be regenerated whenever you get this.
314
+ def cacheable?
315
+ !composite? && (type != :test)
316
+ end
317
+
318
+ # Returns the mtime of the source_path. If this entry is a composite or if the source
319
+ # file does not exist, returns nil
320
+ def source_path_mtime
321
+ (composite? || !File.exists?(source_path)) ? nil : File.mtime(source_path)
322
+ end
323
+
324
+ # Returns a timestamp based on the source_path_mtime. If source_path_mtime is nil, always
325
+ # returns a new timestamp
326
+ def timestamp
327
+ (source_path_mtime || Time.now).to_i.to_s
328
+ end
329
+
330
+ # Returns the content type for this entry. Based on a set of MIME_TYPES borrowed from Rack
331
+ def content_type
332
+ MIME_TYPES[File.extname(build_path)[1..-1]] || 'text/plain'
333
+ end
334
+
335
+ # :stopdoc:
336
+ # From WEBrick.
337
+ MIME_TYPES = {
338
+ "ai" => "application/postscript",
339
+ "asc" => "text/plain",
340
+ "avi" => "video/x-msvideo",
341
+ "bin" => "application/octet-stream",
342
+ "bmp" => "image/bmp",
343
+ "class" => "application/octet-stream",
344
+ "cer" => "application/pkix-cert",
345
+ "crl" => "application/pkix-crl",
346
+ "crt" => "application/x-x509-ca-cert",
347
+ #"crl" => "application/x-pkcs7-crl",
348
+ "css" => "text/css",
349
+ "dms" => "application/octet-stream",
350
+ "doc" => "application/msword",
351
+ "dvi" => "application/x-dvi",
352
+ "eps" => "application/postscript",
353
+ "etx" => "text/x-setext",
354
+ "exe" => "application/octet-stream",
355
+ "gif" => "image/gif",
356
+ "htm" => "text/html",
357
+ "html" => "text/html",
358
+ "rhtml" => "text/html",
359
+ "jpe" => "image/jpeg",
360
+ "jpeg" => "image/jpeg",
361
+ "jpg" => "image/jpeg",
362
+ "lha" => "application/octet-stream",
363
+ "lzh" => "application/octet-stream",
364
+ "mov" => "video/quicktime",
365
+ "mpe" => "video/mpeg",
366
+ "mpeg" => "video/mpeg",
367
+ "mpg" => "video/mpeg",
368
+ "pbm" => "image/x-portable-bitmap",
369
+ "pdf" => "application/pdf",
370
+ "pgm" => "image/x-portable-graymap",
371
+ "png" => "image/png",
372
+ "pnm" => "image/x-portable-anymap",
373
+ "ppm" => "image/x-portable-pixmap",
374
+ "ppt" => "application/vnd.ms-powerpoint",
375
+ "ps" => "application/postscript",
376
+ "qt" => "video/quicktime",
377
+ "ras" => "image/x-cmu-raster",
378
+ "rb" => "text/plain",
379
+ "rd" => "text/plain",
380
+ "rtf" => "application/rtf",
381
+ "sgm" => "text/sgml",
382
+ "sgml" => "text/sgml",
383
+ "tif" => "image/tiff",
384
+ "tiff" => "image/tiff",
385
+ "txt" => "text/plain",
386
+ "xbm" => "image/x-xbitmap",
387
+ "xls" => "application/vnd.ms-excel",
388
+ "xml" => "text/xml",
389
+ "xpm" => "image/x-xpixmap",
390
+ "xwd" => "image/x-xwindowdump",
391
+ "zip" => "application/zip",
392
+ }
393
+ # :startdoc:
394
+
395
+ end
396
+
397
+ end
@@ -0,0 +1,170 @@
1
+
2
+ module SproutCore
3
+
4
+ # You can use these methods basically copy the contents of your templates
5
+ # directory into a target location.
6
+ module GeneratorHelper
7
+
8
+ def apply_template(m, root_dir)
9
+ m.directory root_dir
10
+
11
+ template_directories.each do |d|
12
+ m.directory File.join(root_dir,d)
13
+ end
14
+
15
+ template_files.each do |f|
16
+ f_out = File.join(root_dir,f)
17
+ if f =~ /\.rhtml$/
18
+ m.file f, f_out
19
+ else
20
+ m.template f, f_out
21
+ end
22
+ end
23
+ end
24
+
25
+ def template_directories
26
+ template_files(true)
27
+ end
28
+
29
+ def template_files(directories=false, cur_dir=nil,cur_base=nil)
30
+ if cur_dir.nil?
31
+ cur_dir = File.join(spec.path,'templates')
32
+ cur_base = ''
33
+ end
34
+
35
+ ret = []
36
+ Dir.foreach(cur_dir) do |x|
37
+ next if (x == '.' || x == '..' || x == '.svn')
38
+ base = cur_base + x
39
+ dir = File.join(cur_dir,x)
40
+
41
+ if File.directory?(dir)
42
+ ret << (cur_base + x) if directories
43
+ ret += template_files(directories, dir, base + "/")
44
+ else
45
+ ret << (cur_base + x) if !directories
46
+ end
47
+ end
48
+
49
+ return ret
50
+ end
51
+
52
+ def build_client_directories(m, path)
53
+ parts = File.dirname(path).split('/')
54
+ cpath = []
55
+ parts.each do |p|
56
+ cpath << p
57
+ m.directory File.join(cpath)
58
+ end
59
+ end
60
+
61
+ # Convert the Ruby version of the class name to a JavaScript version.
62
+ def client_class_name
63
+ class_name.gsub('::','.')
64
+ end
65
+
66
+ def client_namespace
67
+ parts = client_class_name.split('.')
68
+ parts.pop
69
+ return parts * '.'
70
+ end
71
+
72
+ def controller_class_name
73
+ ret = client_class_name
74
+ ret += 'Controller' unless ret =~ /Controller$/
75
+ ret
76
+ end
77
+
78
+ def controller_instance_name
79
+ ret = controller_class_name.split('.')
80
+ ret[ret.size-1] = ret.last.underscore.camelize(:lower)
81
+ return ret * "."
82
+ end
83
+
84
+ def view_class_name
85
+ ret = client_class_name
86
+ ret += 'View' unless ret =~ /View$/
87
+ ret
88
+ end
89
+
90
+ # This will convert the file_name provided by Rails to one suitable for
91
+ # the client. i.e. calendar/event => calendar/sub_dir/event
92
+ def client_file_path(sub_dir, ext=nil, to_strip = nil, fp = nil)
93
+ parts = (fp.nil? ? file_path : fp).split('/')
94
+
95
+ # Determine the root dir. Search clients then frameworks.
96
+ loc = @client_location
97
+
98
+ # check for clients
99
+ if loc.nil?
100
+ client_path = File.join(destination_root, "clients")
101
+ app_name = parts.first
102
+ loc = "clients" if File.exists?(client_path) && Dir.new(client_path).include?(app_name)
103
+ end
104
+
105
+ # check for frameworks
106
+ if loc.nil?
107
+ client_path = File.join(destination_root, "frameworks")
108
+ app_name = parts.first
109
+ loc = "frameworks" if File.exists?(client_path) && Dir.new(client_path).include?(app_name)
110
+ end
111
+
112
+ loc = "clients" if loc.nil? # fallback
113
+
114
+ path = parts.insert(parts.size-1,sub_dir).unshift(loc) * '/'
115
+
116
+ # We want to stop the final part of the name for controllers and views.
117
+ if to_strip && (path =~ /_#{to_strip}$/)
118
+ path = path.slice(0,path.size - (to_strip.size + 1))
119
+ end
120
+
121
+ [path,ext].compact * '.'
122
+ end
123
+
124
+ # Returns the base class name, which is the first argument or a default.
125
+ def base_class_name(default_base_class_name = 'SC.Object')
126
+ @args.first || default_base_class_name
127
+ end
128
+
129
+ ###################
130
+ # Borrowed from Rails NamedBase
131
+
132
+ attr_reader :name, :class_name, :singular_name, :plural_name
133
+ attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
134
+ alias_method :file_name, :singular_name
135
+
136
+ def assign_names!(name)
137
+ @name = name
138
+ base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
139
+ @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
140
+ if @class_nesting.empty?
141
+ @class_name = @class_name_without_nesting
142
+ else
143
+ @class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
144
+ end
145
+ end
146
+
147
+ # Extract modules from filesystem-style or ruby-style path:
148
+ # good/fun/stuff
149
+ # Good::Fun::Stuff
150
+ # produce the same results.
151
+ def extract_modules(name)
152
+ modules = name.include?('/') ? name.split('/') : name.split('::')
153
+ name = modules.pop
154
+ path = modules.map { |m| m.underscore }
155
+ file_path = (path + [name.underscore]).join('/')
156
+ nesting = modules.map { |m| m.camelize }.join('::')
157
+ [name, path, file_path, nesting, modules.size]
158
+ end
159
+
160
+ def inflect_names(name)
161
+ camel = name.camelize
162
+ under = camel.underscore
163
+ plural = under.pluralize
164
+ [camel, under, plural]
165
+ end
166
+
167
+ end
168
+ end
169
+
170
+ RubiGen::Base.send(:include,SproutCore::GeneratorHelper)
@@ -0,0 +1,42 @@
1
+ module SproutCore
2
+
3
+ module Helpers
4
+
5
+ module CaptureHelper
6
+
7
+ # Captures the resulting value of the block and returns it
8
+ def capture(*args, &block)
9
+ begin
10
+ buffer = eval('_buf', block.binding)
11
+ rescue
12
+ buffer = nil
13
+ end
14
+
15
+ if buffer.nil?
16
+ block.call(*args).to_s
17
+ else
18
+ pos = buffer.length
19
+ block.call(*args)
20
+
21
+ # get emitted data
22
+ data = buffer[pos..-1]
23
+
24
+ # remove from buffer
25
+ buffer[pos..-1] = ''
26
+
27
+ data
28
+ end
29
+ end
30
+
31
+ # executes the passed block, placing the resulting content into a variable called
32
+ # @content_for_area_name. You can insert this content later by including this
33
+ # variable or by calling yield(:area_name)
34
+ #
35
+ def content_for(name, &block)
36
+ eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,80 @@
1
+ # The helper methods here are used to build the main index template file for
2
+ # a SproutCore application. See the commented index.rhtml in the plugin for
3
+ # example usage.
4
+ #
5
+ module SproutCore
6
+ module Helpers
7
+
8
+ module StaticHelper
9
+
10
+ # This method will return the HTML to link to all the stylesheets required
11
+ # by the named bundle. If you pass no options, the current client will be
12
+ # used.
13
+ #
14
+ # bundle_name = the name of the bundle to render or nil to use the current
15
+ # :language => the language to render. defaults to current language
16
+ #
17
+ def stylesheets_for_client(bundle_name = nil, opts = {})
18
+
19
+ opts[:language] ||= language
20
+
21
+ # Get bundle
22
+ cur_bundle = bundle_name.nil? ? bundle : library.bundle_for(bundle_name)
23
+
24
+ # Convert to a list of required bundles
25
+ all_bundles = cur_bundle.all_required_bundles
26
+
27
+ # For each bundle, get the ordered list of stylsheet urls
28
+ urls = []
29
+ all_bundles.each do |b|
30
+ urls += b.sorted_stylesheet_entries(opts).map { |x| x.url }
31
+ urls += (b.stylesheet_libs || [])
32
+ end
33
+
34
+ # Convert to HTML and return
35
+ urls = urls.map do |url|
36
+ %( <link href="#{url}" rel="stylesheet" type="text/css" />)
37
+ end
38
+ urls.join("\n")
39
+ end
40
+
41
+ # This method will return the HTML to link to all the javascripts required
42
+ # by the client. If you pass no options, the current client will be used.
43
+ #
44
+ # client_name = the name of the client to render or nil to use the current
45
+ # :language => the language to render. defaults to @language.
46
+ #
47
+ def javascripts_for_client(bundle_name = nil, opts = {})
48
+
49
+ opts[:language] ||= language
50
+
51
+ # Get bundle
52
+ cur_bundle = bundle_name.nil? ? bundle : library.bundle_for(bundle_name)
53
+
54
+ # Convert to a list of required bundles
55
+ all_bundles = cur_bundle.all_required_bundles
56
+
57
+ # For each bundle, get the ordered list of stylsheet urls
58
+ urls = []
59
+ all_bundles.each do |b|
60
+ urls += b.sorted_javascript_entries(opts).map { |x| x.url }
61
+ urls += (b.javascript_libs || [])
62
+ end
63
+
64
+ # Convert to HTML and return
65
+ urls = urls.map do |url|
66
+ %( <script type="text/javascript" src="#{url}"></script>)
67
+ end
68
+ urls.join("\n")
69
+ end
70
+
71
+ # Returns the URL for the named resource
72
+ def static_url(resource_name, opts = {})
73
+ opts[:language] ||= language
74
+ entry = bundle.find_resource_entry(resource_name, opts)
75
+ entry.nil? ? '' : entry.url
76
+ end
77
+ end
78
+
79
+ end
80
+ end