card 1.17.4 → 1.18.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 (389) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/card.gemspec +24 -25
  4. data/config/initializers/01_init_ruby_extensions.rb +0 -4
  5. data/config/initializers/inflections.rb +1 -1
  6. data/config/initializers/notification.rb +2 -2
  7. data/db/migrate/20110511221913_require_earlier_migrations.rb +3 -3
  8. data/db/migrate/20120105203350_require_1_8_migrations.rb +3 -3
  9. data/db/migrate/20121111025347_require_1_10_migrations.rb +3 -3
  10. data/db/migrate/20130106052640_table_cleanup.rb +4 -4
  11. data/db/migrate/20130411210957_update_codenames.rb +2 -2
  12. data/db/migrate/20141001105348_move_revisions_to_actions.rb +4 -4
  13. data/db/migrate/20141121172918_rename_card_migration_table.rb +2 -2
  14. data/db/migrate/20141208132159_remove_present_from_reference_table.rb +2 -2
  15. data/db/migrate/20141216053032_better_index_names.rb +9 -9
  16. data/db/migrate_core_cards/20120611203506_rails_inflection_updates.rb +29 -32
  17. data/db/migrate_core_cards/20130411191151_renaming_for_menu.rb +3 -4
  18. data/db/migrate_core_cards/20130411211600_delete_old_related_tab_cards.rb +1 -1
  19. data/db/migrate_core_cards/20130419215612_import_help_text.rb +1 -2
  20. data/db/migrate_core_cards/20130823192433_add_style_cards.rb +3 -3
  21. data/db/migrate_core_cards/20130910183318_move_styles_to_content.rb +2 -3
  22. data/db/migrate_core_cards/20130920214038_jsonize_tinymce.rb +2 -2
  23. data/db/migrate_core_cards/20130920291703_update_stylesheets.rb +1 -2
  24. data/db/migrate_core_cards/20130927191728_account_events.rb +5 -6
  25. data/db/migrate_core_cards/20131016172445_common_css_patch.rb +2 -3
  26. data/db/migrate_core_cards/20140110193325_reset_account_request_type.rb +0 -1
  27. data/db/migrate_core_cards/20140307231621_user_data_to_cards.rb +23 -32
  28. data/db/migrate_core_cards/20140317035504_account_requests_to_signups.rb +1 -7
  29. data/db/migrate_core_cards/20140512155840_add_script_cards.rb +21 -24
  30. data/db/migrate_core_cards/20140629222005_add_email_cards.rb +17 -22
  31. data/db/migrate_core_cards/20140725180118_config_card_updates.rb +2 -2
  32. data/db/migrate_core_cards/20141111083921_delete_machine_output.rb +1 -3
  33. data/db/migrate_core_cards/20141115034214_config_descriptions_etc.rb +2 -2
  34. data/db/migrate_core_cards/20141119001955_make_symlinks_relative.rb +3 -3
  35. data/db/migrate_core_cards/20141120120605_fix_notification_html_message.rb +1 -1
  36. data/db/migrate_core_cards/20141204061304_watchers_to_following.rb +8 -12
  37. data/db/migrate_core_cards/20141208162106_add_ace_script.rb +2 -3
  38. data/db/migrate_core_cards/20141216155251_add_more_following_cards.rb +10 -10
  39. data/db/migrate_core_cards/20150202143810_import_bootstrap_layout.rb +10 -12
  40. data/db/migrate_core_cards/20150220134731_following_to_follow_rule.rb +4 -4
  41. data/db/migrate_core_cards/20150317162412_bootstrap_themes.rb +3 -3
  42. data/db/migrate_core_cards/20150326205655_bootswatch_themes.rb +7 -7
  43. data/db/migrate_core_cards/20150429090551_search_card_context.rb +18 -20
  44. data/db/migrate_core_cards/20150508212032_menu_compatibility.rb +3 -7
  45. data/db/migrate_core_cards/20150510031118_fix_skin_images.rb +2 -3
  46. data/db/migrate_core_cards/20150528084659_add_session_cardtype.rb +3 -3
  47. data/db/migrate_core_cards/20150601133433_add_recent_setting_session_card.rb +4 -4
  48. data/db/migrate_core_cards/20150610171702_add_debugger_session_card.rb +4 -4
  49. data/db/migrate_core_cards/20150610180019_add_recaptcha_key_and_admin_info_cards.rb +5 -11
  50. data/db/migrate_core_cards/20150724123438_update_file_and_image_cards.rb +29 -35
  51. data/db/migrate_core_cards/20150824135418_update_file_history.rb +10 -14
  52. data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +1 -1
  53. data/db/schema.rb +92 -94
  54. data/db/seed/new/card_actions.yml +461 -469
  55. data/db/seed/new/card_acts.yml +154 -172
  56. data/db/seed/new/card_changes.yml +4076 -4031
  57. data/db/seed/new/card_references.yml +1584 -1927
  58. data/db/seed/new/cards.yml +2095 -2112
  59. data/db/seed/test/fixtures/card_actions.yml +1497 -1505
  60. data/db/seed/test/fixtures/card_acts.yml +454 -472
  61. data/db/seed/test/fixtures/card_changes.yml +7309 -7263
  62. data/db/seed/test/fixtures/card_references.yml +2263 -2613
  63. data/db/seed/test/fixtures/cards.yml +3298 -3316
  64. data/db/seed/test/seed.rb +3 -0
  65. data/lib/card.rb +17 -9
  66. data/lib/card/active_record_ext.rb +6 -8
  67. data/lib/card/active_record_helper.rb +42 -32
  68. data/lib/card/auth.rb +3 -3
  69. data/lib/card/cache.rb +4 -4
  70. data/lib/card/cache/persistent.rb +9 -5
  71. data/lib/card/cache/temporary.rb +5 -5
  72. data/lib/card/chunk.rb +1 -1
  73. data/lib/card/codename.rb +3 -2
  74. data/lib/card/content.rb +62 -57
  75. data/lib/card/core_ext.rb +20 -30
  76. data/lib/card/diff.rb +88 -76
  77. data/lib/card/director_register.rb +66 -0
  78. data/lib/card/env.rb +14 -17
  79. data/lib/card/exceptions.rb +7 -9
  80. data/lib/card/format.rb +18 -367
  81. data/lib/card/format/nest.rb +183 -0
  82. data/lib/card/format/permission.rb +63 -0
  83. data/lib/card/format/render.rb +140 -0
  84. data/lib/card/loader.rb +17 -26
  85. data/lib/card/location.rb +6 -6
  86. data/lib/card/mailer.rb +4 -7
  87. data/lib/card/migration.rb +1 -1
  88. data/lib/card/name.rb +3 -6
  89. data/lib/card/query.rb +8 -8
  90. data/lib/card/query/attributes.rb +6 -6
  91. data/lib/card/query/clause.rb +10 -10
  92. data/lib/card/query/join.rb +7 -9
  93. data/lib/card/query/reference.rb +17 -19
  94. data/lib/card/query/sql_statement.rb +2 -2
  95. data/lib/card/query/value.rb +15 -16
  96. data/lib/card/set.rb +106 -209
  97. data/lib/card/set/event.rb +126 -0
  98. data/lib/card/set_pattern.rb +42 -29
  99. data/lib/card/simplecov_helper.rb +19 -19
  100. data/lib/card/spec_helper.rb +40 -16
  101. data/lib/card/stage.rb +72 -0
  102. data/lib/card/stage_director.rb +231 -0
  103. data/lib/card/subcards.rb +56 -24
  104. data/lib/card/subdirector_array.rb +31 -0
  105. data/lib/card/success.rb +15 -18
  106. data/lib/card/version.rb +1 -2
  107. data/lib/card/view_cache.rb +4 -4
  108. data/lib/card/view_name.rb +10 -8
  109. data/lib/cardio.rb +1 -1
  110. data/lib/generators/card.rb +2 -4
  111. data/lib/generators/card/format/format_generator.rb +4 -4
  112. data/lib/generators/card/migration/migration_generator.rb +6 -6
  113. data/lib/generators/card/set/set_generator.rb +5 -6
  114. data/mod/01_core/chunk/include.rb +2 -1
  115. data/mod/01_core/chunk/link.rb +2 -2
  116. data/mod/01_core/chunk/literal.rb +6 -9
  117. data/mod/01_core/chunk/query_reference.rb +1 -1
  118. data/mod/01_core/chunk/reference.rb +2 -2
  119. data/mod/01_core/chunk/uri.rb +52 -63
  120. data/mod/01_core/format/html_format.rb +8 -12
  121. data/mod/01_core/format/text_format.rb +1 -1
  122. data/mod/01_core/set/all/actify.rb +96 -0
  123. data/mod/01_core/set/all/active_card.rb +7 -7
  124. data/mod/01_core/set/all/collection.rb +19 -20
  125. data/mod/01_core/set/all/content.rb +9 -7
  126. data/mod/01_core/set/all/erb.rb +5 -5
  127. data/mod/01_core/set/all/event.rb +60 -0
  128. data/mod/01_core/set/all/fetch.rb +13 -19
  129. data/mod/01_core/set/all/haml.rb +1 -1
  130. data/mod/01_core/set/all/initialize.rb +35 -41
  131. data/mod/01_core/set/all/location_history.rb +3 -5
  132. data/mod/01_core/set/all/name.rb +19 -68
  133. data/mod/01_core/set/all/name_validations.rb +56 -0
  134. data/mod/01_core/set/all/pattern.rb +2 -2
  135. data/mod/01_core/set/all/permissions.rb +14 -20
  136. data/mod/01_core/set/all/phases.rb +9 -200
  137. data/mod/01_core/set/all/references.rb +10 -10
  138. data/mod/01_core/set/all/rules.rb +3 -4
  139. data/mod/01_core/set/all/stages.rb +24 -0
  140. data/mod/01_core/set/all/states.rb +4 -4
  141. data/mod/01_core/set/all/subcards.rb +16 -26
  142. data/mod/01_core/set/all/templating.rb +1 -3
  143. data/mod/01_core/set/all/tracked_attributes.rb +47 -48
  144. data/mod/01_core/set/all/trash.rb +10 -10
  145. data/mod/01_core/set/all/type.rb +9 -8
  146. data/mod/01_core/set/all/utils.rb +10 -14
  147. data/mod/01_core/set/all/view_cache.rb +2 -2
  148. data/mod/01_core/set_pattern/01_all.rb +3 -3
  149. data/mod/01_core/set_pattern/02_all_plus.rb +3 -3
  150. data/mod/01_core/set_pattern/03_type.rb +2 -2
  151. data/mod/01_core/set_pattern/04_star.rb +3 -3
  152. data/mod/01_core/set_pattern/05_rstar.rb +3 -3
  153. data/mod/01_core/set_pattern/06_right.rb +2 -2
  154. data/mod/01_core/set_pattern/07_type_plus_right.rb +2 -2
  155. data/mod/01_core/set_pattern/08_self.rb +1 -1
  156. data/mod/01_core/spec/chunk/literal_spec.rb +7 -8
  157. data/mod/01_core/spec/chunk/uri_spec.rb +140 -142
  158. data/mod/01_core/spec/format/html_format_spec.rb +72 -57
  159. data/mod/01_core/spec/set/all/collection_spec.rb +63 -43
  160. data/mod/01_core/spec/set/all/content_spec.rb +4 -4
  161. data/mod/01_core/spec/set/all/fetch_spec.rb +12 -3
  162. data/mod/01_core/spec/set/all/name_spec.rb +3 -4
  163. data/mod/01_core/spec/set/all/pattern_spec.rb +32 -35
  164. data/mod/01_core/spec/set/all/permissions_spec.rb +17 -5
  165. data/mod/01_core/spec/set/all/phases_spec.rb +0 -1
  166. data/mod/01_core/spec/set/all/references_spec.rb +1 -1
  167. data/mod/01_core/spec/set/all/rules2_spec.rb +79 -91
  168. data/mod/01_core/spec/set/all/rules_spec.rb +63 -56
  169. data/mod/01_core/spec/set/all/templating_spec.rb +0 -1
  170. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +4 -5
  171. data/mod/01_core/spec/set/all/trash_spec.rb +23 -1
  172. data/mod/01_core/spec/set/all/type_spec.rb +2 -5
  173. data/mod/01_history/lib/card/action.rb +8 -10
  174. data/mod/01_history/set/all/actions.rb +2 -4
  175. data/mod/01_history/set/all/content_history.rb +38 -32
  176. data/mod/01_history/set/all/history.rb +20 -17
  177. data/mod/02_basic_types/format/rss_format.rb +0 -1
  178. data/mod/02_basic_types/set/all/all_css.rb +9 -13
  179. data/mod/02_basic_types/set/all/all_csv.rb +14 -17
  180. data/mod/02_basic_types/set/all/all_js.rb +3 -4
  181. data/mod/02_basic_types/set/all/base.rb +2 -2
  182. data/mod/02_basic_types/set/all/file.rb +2 -5
  183. data/mod/02_basic_types/set/all/json.rb +19 -18
  184. data/mod/02_basic_types/set/all/rss.rb +3 -3
  185. data/mod/02_basic_types/set/all/text.rb +1 -3
  186. data/mod/02_basic_types/set/type/html.rb +4 -8
  187. data/mod/02_basic_types/set/type/plain_text.rb +2 -3
  188. data/mod/02_basic_types/set/type/pointer.rb +82 -92
  189. data/mod/02_basic_types/spec/set/all/all_css_spec.rb +2 -2
  190. data/mod/02_basic_types/spec/set/all/all_csv_spec.rb +6 -4
  191. data/mod/02_basic_types/spec/set/all/base_spec.rb +6 -6
  192. data/mod/02_basic_types/spec/set/all/json_spec.rb +8 -8
  193. data/mod/02_basic_types/spec/set/type/plain_text_spec.rb +3 -3
  194. data/mod/02_basic_types/spec/set/type/pointer_spec.rb +29 -32
  195. data/mod/03_machines/lib/card/machine.rb +95 -81
  196. data/mod/03_machines/lib/card/machine_input.rb +35 -34
  197. data/mod/03_machines/set/right/machine_input.rb +1 -1
  198. data/mod/03_machines/set/self/script_ace.rb +2 -3
  199. data/mod/03_machines/set/self/script_card_menu.rb +2 -3
  200. data/mod/03_machines/set/self/script_jquery_helper.rb +2 -2
  201. data/mod/03_machines/set/self/script_slot.rb +2 -2
  202. data/mod/03_machines/set/self/style_bootstrap_compatible.rb +1 -1
  203. data/mod/03_machines/set/self/style_cards.rb +1 -1
  204. data/mod/03_machines/set/self/style_jquery_ui_smoothness.rb +0 -1
  205. data/mod/03_machines/set/type/coffee_script.rb +9 -13
  206. data/mod/03_machines/set/type/css.rb +12 -13
  207. data/mod/03_machines/set/type/java_script.rb +6 -8
  208. data/mod/03_machines/set/type/scss.rb +4 -5
  209. data/mod/03_machines/set/type/skin.rb +3 -6
  210. data/mod/03_machines/spec/lib/shared_machine_examples.rb +31 -38
  211. data/mod/03_machines/spec/lib/shared_machine_input_examples.rb +7 -8
  212. data/mod/03_machines/spec/set/type/coffeescript_spec.rb +19 -13
  213. data/mod/03_machines/spec/set/type/css_spec.rb +22 -16
  214. data/mod/03_machines/spec/set/type/scss_spec.rb +28 -21
  215. data/mod/03_machines/spec/set/type/skin_spec.rb +28 -30
  216. data/mod/04_settings/lib/card/setting.rb +4 -4
  217. data/mod/04_settings/set/abstract/permission.rb +30 -37
  218. data/mod/04_settings/set/right/add_help.rb +3 -3
  219. data/mod/04_settings/set/right/script.rb +4 -5
  220. data/mod/04_settings/set/right/structure.rb +3 -4
  221. data/mod/04_settings/set/right/style.rb +3 -3
  222. data/mod/04_settings/set/self/add_help.rb +1 -1
  223. data/mod/04_settings/set/self/input.rb +1 -1
  224. data/mod/04_settings/set/self/on_create.rb +1 -1
  225. data/mod/04_settings/set/self/options.rb +1 -1
  226. data/mod/04_settings/set/self/options_label.rb +1 -1
  227. data/mod/04_settings/set/type/setting.rb +29 -44
  228. data/mod/04_settings/spec/set/right/comment_spec.rb +9 -12
  229. data/mod/04_settings/spec/set/right/script_spec.rb +7 -7
  230. data/mod/04_settings/spec/set/right/structure_spec.rb +13 -12
  231. data/mod/04_settings/spec/set/right/style_spec.rb +13 -13
  232. data/mod/04_settings/spec/set/type/setting_spec.rb +1 -1
  233. data/mod/05_email/format/email_html_format.rb +1 -1
  234. data/mod/05_email/format/email_text_format.rb +2 -2
  235. data/mod/05_email/lib/card/follow_option.rb +12 -15
  236. data/mod/05_email/set/all/email_html.rb +2 -3
  237. data/mod/05_email/set/all/email_text.rb +3 -3
  238. data/mod/05_email/set/all/follow.rb +14 -22
  239. data/mod/05_email/set/all/notify.rb +11 -11
  240. data/mod/05_email/set/all/observer.rb +7 -8
  241. data/mod/05_email/set/right/bcc.rb +4 -9
  242. data/mod/05_email/set/right/follow.rb +26 -39
  243. data/mod/05_email/set/right/follow_fields.rb +2 -2
  244. data/mod/05_email/set/right/followers.rb +3 -1
  245. data/mod/05_email/set/right/following.rb +13 -16
  246. data/mod/05_email/set/self/always.rb +1 -2
  247. data/mod/05_email/set/self/created.rb +4 -6
  248. data/mod/05_email/set/self/edited.rb +3 -7
  249. data/mod/05_email/set/self/follow_defaults.rb +11 -12
  250. data/mod/05_email/set/self/never.rb +2 -4
  251. data/mod/05_email/set/type/email_template.rb +40 -27
  252. data/mod/05_email/set/type_plus_right/user/follow.rb +159 -157
  253. data/mod/05_email/spec/set/all/follow_spec.rb +28 -37
  254. data/mod/05_email/spec/set/all/notify_spec.rb +21 -26
  255. data/mod/05_email/spec/set/all/observer_spec.rb +58 -37
  256. data/mod/05_email/spec/set/right/followers_spec.rb +9 -14
  257. data/mod/05_email/spec/set/right/following_spec.rb +1 -1
  258. data/mod/05_email/spec/set/self/follow_defaults_spec.rb +1 -1
  259. data/mod/05_standard/lib/carrier_wave/cardmount.rb +9 -9
  260. data/mod/05_standard/lib/file_uploader.rb +8 -13
  261. data/mod/05_standard/lib/image_uploader.rb +8 -9
  262. data/mod/05_standard/set/abstract/attachment.rb +26 -43
  263. data/mod/05_standard/set/all/account.rb +2 -2
  264. data/mod/05_standard/set/all/comment.rb +11 -13
  265. data/mod/05_standard/set/all/error.rb +18 -18
  266. data/mod/05_standard/set/all/event_viz.rb +16 -29
  267. data/mod/05_standard/set/all/links.rb +35 -34
  268. data/mod/05_standard/set/all/list_changes.rb +10 -12
  269. data/mod/05_standard/set/all/rich_html/content.rb +13 -13
  270. data/mod/05_standard/set/all/rich_html/editing.rb +5 -5
  271. data/mod/05_standard/set/all/rich_html/form.rb +22 -26
  272. data/mod/05_standard/set/all/rich_html/header.rb +18 -25
  273. data/mod/05_standard/set/all/rich_html/menu.rb +20 -22
  274. data/mod/05_standard/set/all/rich_html/modal.rb +3 -3
  275. data/mod/05_standard/set/all/rich_html/toolbar.rb +49 -58
  276. data/mod/05_standard/set/all/rich_html/wrapper.rb +40 -41
  277. data/mod/05_standard/set/right/account.rb +26 -14
  278. data/mod/05_standard/set/right/email.rb +2 -2
  279. data/mod/05_standard/set/right/password.rb +6 -5
  280. data/mod/05_standard/set/right/salt.rb +2 -2
  281. data/mod/05_standard/set/right/stats.rb +17 -20
  282. data/mod/05_standard/set/right/token.rb +1 -1
  283. data/mod/05_standard/set/right/when_created.rb +1 -1
  284. data/mod/05_standard/set/right/when_last_edited.rb +1 -1
  285. data/mod/05_standard/set/rstar/rules.rb +3 -3
  286. data/mod/05_standard/set/rstar/rules_editor.rb +39 -39
  287. data/mod/05_standard/set/self/account_links.rb +21 -22
  288. data/mod/05_standard/set/self/admin_info.rb +5 -5
  289. data/mod/05_standard/set/self/alerts.rb +1 -1
  290. data/mod/05_standard/set/self/all.rb +1 -1
  291. data/mod/05_standard/set/self/foot.rb +1 -1
  292. data/mod/05_standard/set/self/head.rb +19 -22
  293. data/mod/05_standard/set/self/navbox.rb +3 -7
  294. data/mod/05_standard/set/self/now.rb +1 -1
  295. data/mod/05_standard/set/self/recent.rb +19 -25
  296. data/mod/05_standard/set/self/search.rb +2 -4
  297. data/mod/05_standard/set/self/signin.rb +6 -6
  298. data/mod/05_standard/set/self/stats.rb +31 -38
  299. data/mod/05_standard/set/self/version.rb +1 -2
  300. data/mod/05_standard/set/type/basic.rb +15 -17
  301. data/mod/05_standard/set/type/cardtype.rb +3 -3
  302. data/mod/05_standard/set/type/date.rb +1 -2
  303. data/mod/05_standard/set/type/file.rb +22 -33
  304. data/mod/05_standard/set/type/image.rb +30 -23
  305. data/mod/05_standard/set/type/layout_type.rb +4 -4
  306. data/mod/05_standard/set/type/list.rb +32 -38
  307. data/mod/05_standard/set/type/listed_by.rb +11 -13
  308. data/mod/05_standard/set/type/number.rb +5 -6
  309. data/mod/05_standard/set/type/phrase.rb +1 -1
  310. data/mod/05_standard/set/type/search_type.rb +25 -23
  311. data/mod/05_standard/set/type/session.rb +2 -3
  312. data/mod/05_standard/set/type/set.rb +46 -51
  313. data/mod/05_standard/set/type/signup.rb +18 -19
  314. data/mod/05_standard/set/type/toggle.rb +5 -5
  315. data/mod/05_standard/set/type/user.rb +6 -6
  316. data/mod/05_standard/spec/chunk/include_spec.rb +115 -98
  317. data/mod/05_standard/spec/chunk/link_spec.rb +58 -31
  318. data/mod/05_standard/spec/chunk/query_reference_spec.rb +12 -14
  319. data/mod/05_standard/spec/set/all/email_html_spec.rb +3 -3
  320. data/mod/05_standard/spec/set/all/error_spec.rb +3 -3
  321. data/mod/05_standard/spec/set/all/history_spec.rb +52 -38
  322. data/mod/05_standard/spec/set/all/links_spec.rb +2 -2
  323. data/mod/05_standard/spec/set/all/rich_html/editing_spec.rb +0 -1
  324. data/mod/05_standard/spec/set/all/rich_html/form_spec.rb +11 -11
  325. data/mod/05_standard/spec/set/all/rich_html/wrapper_spec.rb +4 -4
  326. data/mod/05_standard/spec/set/right/email_spec.rb +1 -4
  327. data/mod/05_standard/spec/set/right/password_spec.rb +4 -7
  328. data/mod/05_standard/spec/set/right/stats_spec.rb +2 -3
  329. data/mod/05_standard/spec/set/right/when_created_spec.rb +1 -1
  330. data/mod/05_standard/spec/set/right/when_last_edited_spec.rb +1 -1
  331. data/mod/05_standard/spec/set/rstar/rules_spec.rb +6 -6
  332. data/mod/05_standard/spec/set/self/all_spec.rb +11 -13
  333. data/mod/05_standard/spec/set/self/head_spec.rb +1 -3
  334. data/mod/05_standard/spec/set/self/navbox_spec.rb +1 -1
  335. data/mod/05_standard/spec/set/self/now_spec.rb +2 -2
  336. data/mod/05_standard/spec/set/self/signin_spec.rb +1 -1
  337. data/mod/05_standard/spec/set/self/stats_spec.rb +1 -1
  338. data/mod/05_standard/spec/set/self/version_spec.rb +2 -2
  339. data/mod/05_standard/spec/set/type/cardtype_spec.rb +3 -4
  340. data/mod/05_standard/spec/set/type/date_spec.rb +1 -1
  341. data/mod/05_standard/spec/set/type/email_template_spec.rb +5 -5
  342. data/mod/05_standard/spec/set/type/file_spec.rb +50 -28
  343. data/mod/05_standard/spec/set/type/html_spec.rb +12 -7
  344. data/mod/05_standard/spec/set/type/image_spec.rb +55 -45
  345. data/mod/05_standard/spec/set/type/layout_type_spec.rb +2 -2
  346. data/mod/05_standard/spec/set/type/listed_by_spec.rb +2 -2
  347. data/mod/05_standard/spec/set/type/number_spec.rb +1 -1
  348. data/mod/05_standard/spec/set/type/phrase_spec.rb +1 -1
  349. data/mod/05_standard/spec/set/type/search_type_spec.rb +15 -16
  350. data/mod/05_standard/spec/set/type/set_spec.rb +16 -17
  351. data/mod/05_standard/spec/set/type/signup_spec.rb +7 -5
  352. data/mod/05_standard/spec/set/type/toggle_spec.rb +4 -4
  353. data/mod/05_standard/spec/set/type/uri_spec.rb +11 -11
  354. data/mod/05_standard/spec/set/type/user_spec.rb +0 -1
  355. data/mod/06_bootstrap/set/all/bootstrap/form.rb +9 -10
  356. data/mod/06_bootstrap/set/all/bootstrap/helper.rb +22 -27
  357. data/mod/06_bootstrap/set/all/bootstrap/wrapper.rb +1 -2
  358. data/mod/06_bootstrap/set/all/rich_bootstrap.rb +1 -3
  359. data/mod/06_bootstrap/set/self/bootstrap_cards.rb +2 -2
  360. data/mod/06_bootstrap/set/self/bootstrap_js.rb +2 -2
  361. data/mod/06_bootstrap/set/self/bootswatch_shared.rb +19 -19
  362. data/mod/06_bootstrap/set/self/smartmenu_css.rb +2 -2
  363. data/mod/06_bootstrap/set/self/smartmenu_js.rb +3 -3
  364. data/mod/06_bootstrap/spec/set/all/bootstrap/form_spec.rb +5 -5
  365. data/spec/lib/card/action_spec.rb +4 -4
  366. data/spec/lib/card/cache_spec.rb +3 -5
  367. data/spec/lib/card/chunk_spec.rb +6 -8
  368. data/spec/lib/card/codename_spec.rb +4 -6
  369. data/spec/lib/card/content_spec.rb +12 -17
  370. data/spec/lib/card/diff_spec.rb +59 -61
  371. data/spec/lib/card/format_spec.rb +55 -34
  372. data/spec/lib/card/loader_spec.rb +35 -37
  373. data/spec/lib/card/name_spec.rb +159 -145
  374. data/spec/lib/card/query_spec.rb +4 -4
  375. data/spec/lib/card/reference_spec.rb +24 -24
  376. data/spec/lib/card/set_pattern_spec.rb +3 -3
  377. data/spec/lib/card/stage_director_spec.rb +218 -0
  378. data/spec/lib/card/subcards_spec.rb +12 -16
  379. data/spec/lib/card/success_spec.rb +16 -18
  380. data/spec/lib/card/view_cache_spec.rb +1 -1
  381. data/spec/mailers/mailer_spec.rb +3 -5
  382. data/spec/models/card/cardtype_spec.rb +40 -51
  383. data/spec/models/card/create_spec.rb +58 -39
  384. data/spec/models/card/trash_spec.rb +23 -32
  385. data/spec/models/card/type_transition_spec.rb +41 -32
  386. data/spec/models/card/validation_spec.rb +13 -15
  387. data/spec/models/card_spec.rb +48 -59
  388. data/spec/spec_helper.rb +26 -31
  389. metadata +16 -2
@@ -0,0 +1,66 @@
1
+ class Card
2
+ def act opts={}
3
+ if !DirectorRegister.act_card
4
+ DirectorRegister.clear
5
+ self.director = nil
6
+ DirectorRegister.act_card = self
7
+ main_act_block = true
8
+ if opts[:success]
9
+ Env[:success] = Success.new(cardname, Env.params[:success])
10
+ end
11
+ else
12
+ main_act_block = false
13
+ end
14
+ yield
15
+ ensure
16
+ DirectorRegister.clear if main_act_block
17
+ end
18
+
19
+ def self.new_director card, opts={}
20
+ if opts[:parent]
21
+ StageSubdirector.new card, opts
22
+ elsif DirectorRegister.act_card &&
23
+ DirectorRegister.act_card != card &&
24
+ DirectorRegister.act_card.director.running?
25
+ DirectorRegister.act_card.director.subdirectors.add(card)
26
+ else
27
+ StageDirector.new card
28
+ end
29
+ end
30
+
31
+ class DirectorRegister
32
+ cattr_accessor :act_card
33
+
34
+ class << self
35
+ def act_director
36
+ return unless DirectorRegister.act_card
37
+ DirectorRegister.act_card.director
38
+ end
39
+
40
+ def directors
41
+ @directors ||= {}
42
+ end
43
+
44
+ def clear
45
+ DirectorRegister.act_card = nil
46
+ directors.each_pair do |card, _dir|
47
+ card.director = nil
48
+ end
49
+ @directors = nil
50
+ end
51
+
52
+ def fetch card, opts={}
53
+ directors[card] ||= Card.new_director card, opts
54
+ end
55
+
56
+ def add director
57
+ directors[director.card] = director
58
+ end
59
+
60
+ def delete director
61
+ return unless @directors
62
+ @directors.delete director.card
63
+ end
64
+ end
65
+ end
66
+ end
data/lib/card/env.rb CHANGED
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  class Card
4
2
  require 'card/location'
5
3
 
@@ -16,8 +14,10 @@ class Card
16
14
  self[:ip] = c.request.remote_ip
17
15
  self[:ajax] = c.request.xhr? || c.request.params[:simulate_xhr]
18
16
  self[:html] = [nil, 'html'].member?(c.params[:format])
19
- self[:host] = Card.config.override_host || c.request.env['HTTP_HOST']
20
- self[:protocol] = Card.config.override_protocol || c.request.protocol
17
+ self[:host] = Card.config.override_host ||
18
+ c.request.env['HTTP_HOST']
19
+ self[:protocol] = Card.config.override_protocol ||
20
+ c.request.protocol
21
21
  end
22
22
  end
23
23
 
@@ -29,7 +29,6 @@ class Card
29
29
  @@env[key.to_sym] = value
30
30
  end
31
31
 
32
-
33
32
  def params
34
33
  self[:params] ||= {}
35
34
  end
@@ -56,9 +55,9 @@ class Card
56
55
 
57
56
  def method_missing method_id, *args
58
57
  case args.length
59
- when 0 ; self[ method_id ]
60
- when 1 ; self[ method_id ] = args[0]
61
- else ; super
58
+ when 0 then self[method_id]
59
+ when 1 then self[method_id] = args[0]
60
+ else super
62
61
  end
63
62
  end
64
63
  end
@@ -66,8 +65,6 @@ class Card
66
65
  # session history helpers: we keep a history stack so that in the case of
67
66
  # card removal we can crawl back up to the last un-removed location
68
67
  module LocationHistory
69
- #include Card::Location
70
-
71
68
  def location_history
72
69
  session[:history] ||= [Card::Location.card_path('')]
73
70
  session[:history].shift if session[:history].size > 5
@@ -75,14 +72,17 @@ class Card
75
72
  end
76
73
 
77
74
  def save_location card
78
- return if Env.ajax? || !Env.html? || !card.known? ||
79
- (card.codename == 'signin')
75
+ return unless save_location?(card)
80
76
  discard_locations_for card
81
77
  session[:previous_location] =
82
78
  Card::Location.card_path card.cardname.url_key
83
79
  location_history.push previous_location
84
80
  end
85
81
 
82
+ def save_location? card
83
+ !Env.ajax? && Env.html? && card.known? && (card.codename != 'signin')
84
+ end
85
+
86
86
  def previous_location
87
87
  return unless location_history
88
88
  session[:previous_location] ||= location_history.last
@@ -106,16 +106,13 @@ class Card
106
106
  session.delete :interrupted_action
107
107
  end
108
108
 
109
- def url_key_for_location(location)
110
- location.match( /\/([^\/]*$)/ ) ? $1 : nil
109
+ def url_key_for_location location
110
+ (%r{/([^/]*$)} =~ location) ? Regexp.last_match[1] : nil
111
111
  end
112
112
  end
113
113
 
114
114
  extend LocationHistory
115
-
116
115
  end
117
116
 
118
-
119
-
120
117
  Env.reset
121
118
  end
@@ -1,22 +1,22 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  class Card
4
- class Error < StandardError #code problem
4
+ class Error < StandardError # code problem
5
5
  cattr_accessor :current
6
6
  end
7
-
7
+
8
8
  class Oops < Error # wagneer problem (rename!)
9
9
  end
10
-
10
+
11
11
  class BadQuery < Error
12
12
  end
13
-
13
+
14
14
  class NotFound < StandardError
15
15
  end
16
-
16
+
17
17
  class PermissionDenied < Error
18
18
  attr_reader :card
19
-
19
+
20
20
  def initialize card
21
21
  @card = card
22
22
  super build_message
@@ -30,7 +30,7 @@ class Card
30
30
  end
31
31
  end
32
32
  end
33
-
33
+
34
34
  class Abort < StandardError
35
35
  attr_reader :status
36
36
 
@@ -38,7 +38,5 @@ class Card
38
38
  @status = status
39
39
  super msg
40
40
  end
41
-
42
41
  end
43
-
44
42
  end
data/lib/card/format.rb CHANGED
@@ -3,12 +3,15 @@
3
3
  class Card
4
4
  class Format
5
5
  include Card::Location
6
+ include Nest
7
+ include Permission
8
+ include Render
6
9
 
7
10
  DEPRECATED_VIEWS = { view: :open, card: :open, line: :closed,
8
- bare: :core, naked: :core }
11
+ bare: :core, naked: :core }.freeze
9
12
  INCLUSION_MODES = { closed: :closed, closed_content: :closed, edit: :edit,
10
13
  layout: :layout, new: :edit, setup: :edit,
11
- normal: :normal, template: :template }
14
+ normal: :normal, template: :template }.freeze
12
15
  # FIXME: should be set in views
13
16
 
14
17
  cattr_accessor :ajax_call, :registered
@@ -19,7 +22,7 @@ class Card
19
22
  end
20
23
 
21
24
  attr_reader :card, :root, :parent, :main_opts
22
- attr_accessor :form, :error_status, :inclusion_opts
25
+ attr_accessor :form, :error_status, :nest_opts
23
26
 
24
27
  class << self
25
28
  @@registered = []
@@ -70,9 +73,7 @@ class Card
70
73
 
71
74
  def format_ancestry
72
75
  ancestry = [self]
73
- unless self == Card::Format
74
- ancestry = ancestry + superclass.format_ancestry
75
- end
76
+ ancestry += superclass.format_ancestry unless self == Card::Format
76
77
  ancestry
77
78
  end
78
79
 
@@ -84,9 +85,7 @@ class Card
84
85
  # ~~~~~ INSTANCE METHODS
85
86
 
86
87
  def initialize card, opts={}
87
- unless (@card = card)
88
- raise Card::Error, 'format initialized without card'
89
- end
88
+ raise Card::Error, 'format initialized without card' unless (@card = card)
90
89
  opts.each do |key, value|
91
90
  instance_variable_set "@#{key}", value
92
91
  end
@@ -103,11 +102,11 @@ class Card
103
102
  def get_context_names
104
103
  case
105
104
  when @context_names
106
- part_keys = @card.cardname.part_names.map &:key
105
+ part_keys = @card.cardname.part_names.map(&:key)
107
106
  @context_names.reject { |n| !part_keys.include? n.key }
108
107
  when params[:slot]
109
108
  context_name_list = params[:slot][:name_context].to_s
110
- context_name_list.split(',').map &:to_name
109
+ context_name_list.split(',').map(&:to_name)
111
110
  else
112
111
  []
113
112
  end
@@ -121,18 +120,6 @@ class Card
121
120
  end
122
121
  end
123
122
 
124
- def inclusion_defaults nested_card
125
- @inclusion_defaults ||= begin
126
- defaults = get_inclusion_defaults(nested_card).clone
127
- defaults.merge! @inclusion_opts if @inclusion_opts
128
- defaults
129
- end
130
- end
131
-
132
- def get_inclusion_defaults _nested_card
133
- { view: :name }
134
- end
135
-
136
123
  def params
137
124
  Env.params
138
125
  end
@@ -147,9 +134,9 @@ class Card
147
134
 
148
135
  def showname title=nil
149
136
  if title
150
- title.to_name.to_absolute_name(card.cardname).to_show *@context_names
137
+ title.to_name.to_absolute_name(card.cardname).to_show(*@context_names)
151
138
  else
152
- @showname ||= card.cardname.to_show *@context_names
139
+ @showname ||= card.cardname.to_show(*@context_names)
153
140
  end
154
141
  end
155
142
 
@@ -184,10 +171,13 @@ class Card
184
171
 
185
172
  def method_missing method, *opts, &proc
186
173
  if method =~ /(_)?(optional_)?render(_(\w+))?/
187
- view = $3 ? $4 : opts.shift
174
+ view = Regexp.last_match(3) ? Regexp.last_match(4) : opts.shift
188
175
  args = opts[0] ? opts.shift.clone : {}
189
- args.merge!(optional: true, default_visibility: opts.shift) if $2
190
- args[:skip_permissions] = true if $1
176
+ if Regexp.last_match(2)
177
+ args[:optional] = true
178
+ args[:default_visibility] = opts.shift
179
+ end
180
+ args[:skip_permissions] = true if Regexp.last_match(1)
191
181
  render view, args
192
182
  else
193
183
  proc = proc { |*a| raw yield *a } if proc
@@ -196,135 +186,10 @@ class Card
196
186
  end
197
187
  end
198
188
 
199
- #
200
- # ---------- Rendering ------------
201
- #
202
-
203
- def render view, args={}
204
- view = canonicalize_view view
205
- return if hidden_view? view, args
206
- view = ok_view view, args
207
- current_view(view) do
208
- args = default_render_args view, args
209
- with_inclusion_mode view do
210
- Card::ViewCache.fetch(self, view, args) do
211
- method = view_method view, args
212
- method.arity == 0 ? method.call : method.call(args)
213
- end
214
- end
215
- end
216
- rescue => e
217
- rescue_view e, view
218
- end
219
-
220
- def view_method view, args
221
- method "_view_#{view}"
222
- rescue
223
- args[:unsupported_view] = view
224
- method '_view_unsupported_view'
225
- end
226
-
227
- def hidden_view? view, args
228
- args.delete(:optional) && !show_view?(view, args)
229
- end
230
-
231
- def show_view? view, args
232
- default = args.delete(:default_visibility) || :show # FIXME: - ugly
233
- api_option = args["optional_#{view}".to_sym]
234
- case
235
- # permanent visibility specified in code
236
- when api_option == :always then true
237
- when api_option == :never then false
238
- else
239
- # wagneer can override code settings
240
- contextual_setting = nest_arg_visibility(view, args) || api_option
241
- case contextual_setting
242
- when :show then true
243
- when :hide then false
244
- else default == :show
245
- end
246
- end
247
- end
248
-
249
- def nest_arg_visibility view, args
250
- [:show, :hide].each do |setting|
251
- return setting if parse_view_visibility(args[setting]).member?(view)
252
- end
253
- false
254
- end
255
-
256
- def parse_view_visibility val
257
- case val
258
- when NilClass then []
259
- when Array then val
260
- when String then val.split(/[\s,]+/)
261
- else raise Card::Error, "bad show/hide argument: #{val}"
262
- end.map { |view| canonicalize_view view }
263
- end
264
-
265
- def default_render_args view, a=nil
266
- args =
267
- case a
268
- when nil then {}
269
- when Hash then a.clone
270
- when Array then a[0].merge a[1]
271
- else raise Card::Error, "bad render args: #{a}"
272
- end
273
-
274
- default_method = "default_#{view}_args"
275
- if respond_to? default_method
276
- send default_method, args
277
- end
278
- args
279
- end
280
-
281
- def rescue_view e, view
282
- if Rails.env =~ /^cucumber|test$/
283
- raise e
284
- else
285
- Rails.logger.info "\nError rendering #{error_cardname} / #{view}: "\
286
- "#{e.class} : #{e.message}"
287
- Card::Error.current = e
288
- card.notable_exception_raised
289
- if (debug = Card[:debugger]) && debug.content == 'on'
290
- raise e
291
- else
292
- rendering_error e, view
293
- end
294
- end
295
- end
296
-
297
- def current_view view
298
- old_view = @current_view
299
- @current_view = view
300
- yield
301
- ensure
302
- @current_view = old_view
303
- end
304
-
305
- def error_cardname
306
- card && card.name.present? ? card.name : 'unknown card'
307
- end
308
-
309
- def rendering_error _exception, view
310
- "Error rendering: #{error_cardname} (#{view} view)"
311
- end
312
-
313
189
  #
314
190
  # ------------- Sub Format and Inclusion Processing ------------
315
191
  #
316
192
 
317
- def subformat subcard
318
- subcard = Card.fetch(subcard, new: {}) if subcard.is_a?(String)
319
- self.class.new subcard,
320
- parent: self, depth: @depth + 1, root: @root,
321
- # FIXME: - the following four should not be hard-coded
322
- # here. need a generalized mechanism
323
- # for attribute inheritance
324
- context_names: @context_names, mode: @mode,
325
- mainline: @mainline, form: @form
326
- end
327
-
328
193
  def process_content override_content=nil, opts={}
329
194
  process_content_object(override_content, opts).to_s
330
195
  end
@@ -345,228 +210,14 @@ class Card
345
210
  end
346
211
  end
347
212
 
348
- def ok_view view, args={}
349
- return view if args.delete :skip_permissions
350
- approved_view = approved_view view, args
351
- args[:denied_view] = view if approved_view != view
352
- if focal? && (error_code = @@error_code[approved_view])
353
- root.error_status = error_code
354
- end
355
- approved_view
356
- end
357
-
358
- def approved_view view, args={}
359
- case
360
- when @depth >= Card.config.max_depth
361
- # prevent recursion. @depth tracks subformats
362
- :too_deep
363
- when @@perms[view] == :none
364
- # permission skipping specified in view definition
365
- view
366
- when args.delete(:skip_permissions)
367
- # permission skipping specified in args
368
- view
369
- when !card.known? && !tagged(view, :unknown_ok)
370
- # handle unknown cards (where view not exempt)
371
- view_for_unknown view, args
372
- else
373
- # run explicit permission checks
374
- permitted_view view, args
375
- end
376
- end
377
-
378
213
  def tagged view, tag
379
214
  self.class.tagged view, tag
380
215
  end
381
216
 
382
- def permitted_view view, args
383
- perms_required = @@perms[view] || :read
384
- args[:denied_task] =
385
- if Proc === perms_required
386
- :read if !(perms_required.call self) # read isn't quite right
387
- else
388
- [perms_required].flatten.find { |task| !ok? task }
389
- end
390
-
391
- if args[:denied_task]
392
- @@denial[view] || :denial
393
- else
394
- view
395
- end
396
- end
397
-
398
- def ok? task
399
- task = :create if task == :update && card.new_card?
400
- @ok ||= {}
401
- @ok[task] = card.ok? task if @ok[task].nil?
402
- @ok[task]
403
- end
404
-
405
- def view_for_unknown _view, _args
406
- # note: overridden in HTML
407
- focal? ? :not_found : :missing
408
- end
409
-
410
- def canonicalize_view view
411
- return if view.blank?
412
- view_key = view.to_viewname.key.to_sym
413
- DEPRECATED_VIEWS[view_key] || view_key
414
- end
415
-
416
- def with_inclusion_mode mode
417
- if (switch_mode = INCLUSION_MODES[mode]) && @mode != switch_mode
418
- old_mode, @mode = @mode, switch_mode
419
- @inclusion_defaults = nil
420
- end
421
- result = yield
422
- if old_mode
423
- @inclusion_defaults = nil
424
- @mode = old_mode
425
- end
426
- result
427
- end
428
-
429
- def prepare_nest opts
430
- @char_count ||= 0
431
- opts ||= {}
432
-
433
- case
434
- when opts.has_key?(:comment)
435
- # commented nest
436
- opts[:comment]
437
- when @mode == :closed && @char_count > Card.config.max_char_count
438
- # move on; content out of view
439
- ''
440
- when opts[:inc_name] == '_main' && show_layout? && @depth == 0
441
- # the main card within a layout
442
- expand_main opts
443
- else
444
- # standard nest
445
- result = nest fetch_nested_card(opts), opts
446
- @char_count += result.length if @mode == :closed && result
447
- result
448
- end
449
- end
450
-
451
- def expand_main opts
452
- opts.merge! root.main_opts if root.main_opts
453
- legacy_main_opts_tweaks! opts
454
-
455
- with_inclusion_mode :normal do
456
- @mainline = true
457
- result = wrap_main nest(root.card, opts)
458
- @mainline = false
459
- result
460
- end
461
- end
462
-
463
- def legacy_main_opts_tweaks! opts
464
- if (val = params[:size]) && val.present?
465
- opts[:size] = val.to_sym
466
- end
467
-
468
- if (val = params[:item]) && val.present?
469
- opts[:items] = (opts[:items] || {}).reverse_merge view: val.to_sym
470
- end
471
- end
472
-
473
- def wrap_main content
474
- content # no wrapping in base format
475
- end
476
-
477
- def nest nested_card, opts={}
478
- # ActiveSupport::Notifications.instrument('card', message:
479
- # "nest: #{nested_card.name}, #{opts}") do
480
- opts.delete_if { |_k, v| v.nil? }
481
- opts.reverse_merge! inclusion_defaults(nested_card)
482
-
483
- sub = nil
484
- if opts[:inc_name] =~ /^_(self)?$/
485
- sub = self
486
- else
487
- sub = subformat nested_card
488
- sub.inclusion_opts = opts[:items] ? opts[:items].clone : {}
489
- end
490
-
491
- view = canonicalize_view opts.delete :view
492
- opts[:home_view] = [:closed, :edit].member?(view) ? :open : view
493
- # FIXME: special views should be represented in view definitions
494
-
495
- view =
496
- case @mode
497
- when :edit then view_in_edit_mode(view, nested_card)
498
- when :template then :template_rule
499
- when :closed then view_in_closed_mode(view, nested_card)
500
- else view
501
- end
502
-
503
- sub.optional_render view, opts
504
- # end
505
- end
506
-
507
- def view_in_edit_mode homeview, nested_card
508
- not_in_form =
509
- @@perms[homeview] == :none || # view configured not to keep in form
510
- nested_card.structure || # not yet nesting structures
511
- nested_card.key.blank? # eg {{_self|type}} on new cards
512
-
513
- not_in_form ? :blank : :edit_in_form
514
- end
515
-
516
- def view_in_closed_mode homeview, nested_card
517
- approved_view = @@closed[homeview]
518
- case
519
- when approved_view == true then homeview
520
- when @@error_code[homeview] then homeview
521
- when approved_view then approved_view
522
- when !nested_card.known? then :closed_missing
523
- else :closed_content
524
- end
525
- end
526
-
527
- def get_inclusion_content cardname
528
- content = params[cardname.to_s.tr('+', '_')]
529
-
530
- # CLEANME This is a hack so plus cards re-populate on failed signups
531
- p = params['subcards']
532
- if p && (card_params = p[cardname.to_s])
533
- content = card_params['content']
534
- end
535
- content if content.present? # returns nil for empty string
536
- end
537
-
538
- def fetch_nested_card options
539
- args = { name: options[:inc_name], type: options[:type], supercard: card }
540
- args.delete(:supercard) if options[:inc_name].strip.blank?
541
- # special case. gets absolutized incorrectly. fix in smartname?
542
- if options[:inc_name] =~ /^_main\+/
543
- # FIXME: this is a rather hacky (and untested) way to get @superleft
544
- # to work on new cards named _main+whatever
545
- args[:name] = args[:name].gsub /^_main\+/, '+'
546
- args[:supercard] = root.card
547
- end
548
- if (content = get_inclusion_content options[:inc_name])
549
- args[:content] = content
550
- end
551
- Card.fetch options[:inc_name], new: args
552
- end
553
-
554
- def default_item_view
555
- :name
556
- end
557
-
558
217
  #
559
218
  # ------------ LINKS ---------------
560
219
  #
561
220
 
562
- def add_class options, klass
563
- options[:class] = [options[:class], klass].flatten.compact * ' '
564
- end
565
-
566
- def unique_id
567
- "#{card.key}-#{Time.now.to_i}-#{rand(3)}"
568
- end
569
-
570
221
  def format_date date, include_time=true
571
222
  # using DateTime because Time doesn't support %e on some platforms
572
223
  if include_time