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
data/db/seed/test/seed.rb CHANGED
@@ -210,5 +210,8 @@ class SharedData
210
210
  first.update_attributes! content: 'chicken'
211
211
  first.update_attributes! content: 'chick'
212
212
 
213
+ # Card['*all+*style' ].ensure_machine_output
214
+ # Card['*all+*script'].ensure_machine_output
215
+ # (ie9 = Card[:script_html5shiv_printshiv]) && ie9.ensure_machine_output
213
216
  end
214
217
  end
data/lib/card.rb CHANGED
@@ -32,6 +32,8 @@ class Card < ActiveRecord::Base
32
32
  require_dependency 'card/reference'
33
33
  require_dependency 'card/subcards'
34
34
  require_dependency 'card/view_cache'
35
+ require_dependency 'card/stage_director'
36
+ require_dependency 'card/director_register'
35
37
 
36
38
  has_many :references_in, class_name: :Reference, foreign_key: :referee_id
37
39
  has_many :references_out, class_name: :Reference, foreign_key: :referer_id
@@ -40,7 +42,7 @@ class Card < ActiveRecord::Base
40
42
  has_many :drafts, -> { where(draft: true).order :id }, class_name: :Action
41
43
 
42
44
  cattr_accessor :set_patterns, :serializable_attributes, :error_codes,
43
- :set_specific_attributes
45
+ :set_specific_attributes, :current_act
44
46
  @@set_patterns = []
45
47
  @@error_codes = {}
46
48
 
@@ -52,20 +54,26 @@ class Card < ActiveRecord::Base
52
54
  :update_all_users, # if the above is wrong then this one too
53
55
  :silent_change, # and this probably too
54
56
  :remove_rule_stash,
55
- :last_action_id_before_edit
57
+ :last_action_id_before_edit,
58
+ :skip_phases
56
59
  )
57
60
 
58
61
  attr_accessor :follower_stash
59
62
 
60
- define_callbacks :prepare, :approve, :store, :stored, :extend, :subsequent,
61
- :select_action, :show, :handle
63
+ define_callbacks :select_action, :show_page, :handle, :act,
64
+ :initialize_stage,
65
+ :prepare_to_validate_stage, :validate_stage,
66
+ :prepare_to_store_stage, :store_stage,
67
+ :finalize_stage,
68
+ :integrate_stage, :integrate_with_delay_stage
62
69
 
63
- before_validation :prepare
64
- before_validation :approve
65
- around_save :store
66
- after_save :extend
70
+ before_validation :validation_phase, if: -> { run_phases? }
71
+ around_save :storage_phase
72
+ after_save :integration_phase, if: -> { run_phases? }
73
+ after_commit :clean_up, if: -> { run_phases? }
74
+ after_rollback :clean_up, if: -> { run_phases? }
67
75
 
68
- TRACKED_FIELDS = %w(name type_id db_content trash)
76
+ TRACKED_FIELDS = %w(name type_id db_content trash).freeze
69
77
  extend CarrierWave::Mount
70
78
  ActiveSupport.run_load_hooks(:card, self)
71
79
  end
@@ -1,10 +1,9 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module ActiveRecord
3
-
4
3
  module ConnectionAdapters
5
4
  class AbstractAdapter
6
- def match(string)
7
- raise "match not implemented"
5
+ def match _string
6
+ raise 'match not implemented'
8
7
  end
9
8
 
10
9
  def cast_types
@@ -17,13 +16,13 @@ module ActiveRecord
17
16
  end
18
17
 
19
18
  class PostgreSQLAdapter
20
- def match(string)
19
+ def match string
21
20
  "~* #{string}"
22
21
  end
23
22
  end
24
23
 
25
24
  module MysqlCommon
26
- def match(string)
25
+ def match string
27
26
  "REGEXP #{string}"
28
27
  end
29
28
 
@@ -45,14 +44,14 @@ module ActiveRecord
45
44
  end
46
45
 
47
46
  class SQLiteAdapter
48
- def match(string)
47
+ def match string
49
48
  "REGEXP #{string}"
50
49
  end
51
50
  end
52
51
  end
53
52
 
54
53
  module Transactions
55
- #FIXME!!
54
+ # FIXME!!
56
55
  # the following code is already in Rails 4 (see https://github.com/rails/rails/commit/c8792c7b2ea4f5fe7a5610225433ea8dd8d0f83e)
57
56
  # it allows manual rollbacks in after_save (eg store events) to reset the object correctly
58
57
  # hopefully we can soon get rid of this code!
@@ -73,5 +72,4 @@ module ActiveRecord
73
72
  status
74
73
  end
75
74
  end
76
-
77
75
  end
@@ -1,42 +1,52 @@
1
- module Card::ActiveRecordHelper
2
- def create_card args
3
- resolve_name_conflict args
4
- Card.create! args
5
- end
1
+ class Card
2
+ module ActiveRecordHelper
3
+ def create_card args
4
+ resolve_name_conflict args
5
+ Card.create! args
6
+ end
6
7
 
7
- def create_card! args
8
- create_card args.reverse_merge(rename_if_conflict: :new)
9
- end
8
+ def create_card! args
9
+ create_card args.reverse_merge(rename_if_conflict: :new)
10
+ end
10
11
 
11
- def update_card name, args
12
- resolve_name_conflict args
13
- Card[name].update_attributes! args
14
- end
12
+ def update_card name, args
13
+ resolve_name_conflict args
14
+ Card[name].update_attributes! args
15
+ end
15
16
 
16
- def update_card! args
17
- update_card args.reverse_merge(rename_if_conflict: :new)
18
- end
17
+ def update_card! args
18
+ update_card args.reverse_merge(rename_if_conflict: :new)
19
+ end
19
20
 
20
- def create_or_update name_or_args, args=nil
21
- name = args ? name_or_args : name_or_args[:name]
22
- args ||= name_or_args
23
- if Card[name]
24
- update_card name, args
25
- else
26
- create_card args.merge(name: name)
21
+ def create_or_update name_or_args, args={}
22
+ if name_or_args.is_a?(Hash)
23
+ name = name_or_args.delete :name
24
+ args = name_or_args
25
+ else
26
+ name = name_or_args
27
+ end
28
+ if Card[name]
29
+ update_card name, args
30
+ else
31
+ create_card args.merge(name: name)
32
+ end
27
33
  end
28
- end
29
34
 
30
- def create_or_update! name_or_args, args=nil
31
- name = args ? name_or_args : name_or_args[:name]
32
- args ||= {}
33
- create_or_update name, args.reverse_merge(rename_if_conflict: :new)
34
- end
35
+ def create_or_update! name_or_args, args=nil
36
+ if name_or_args.is_a?(Hash)
37
+ name = name_or_args.delete(:name)
38
+ args = name_or_args
39
+ else
40
+ name = name_or_args
41
+ args ||= {}
42
+ end
43
+ create_or_update name, args.reverse_merge(rename_if_conflict: :new)
44
+ end
35
45
 
36
- def resolve_name_conflict args
37
- rename = args.delete :rename_if_conflict
38
- if rename
46
+ def resolve_name_conflict args
47
+ rename = args.delete :rename_if_conflict
48
+ return unless rename
39
49
  args[:name] = Card.uniquify_name args[:name], rename
40
50
  end
41
51
  end
42
- end
52
+ end
data/lib/card/auth.rb CHANGED
@@ -5,11 +5,11 @@ class Card
5
5
  @@as_card = @@as_id = @@current_id = @@current = nil
6
6
  @@simulating_setup_need = nil
7
7
 
8
- SETUP_COMPLETED_KEY = 'SETUP_COMPLETED'
8
+ SETUP_COMPLETED_KEY = 'SETUP_COMPLETED'.freeze
9
9
  DEFAULT_RECAPTCHA_SETTINGS = {
10
10
  recaptcha_public_key: '6LeoHfESAAAAAN1NdQeYHREq4jTSQhu1foEzv6KC',
11
11
  recaptcha_private_key: '6LeoHfESAAAAAHLZpn7ijrO4_KGLEr2nGL4qjjis'
12
- }
12
+ }.freeze
13
13
 
14
14
  # after_save :reset_instance_cache
15
15
 
@@ -193,7 +193,7 @@ class Card
193
193
 
194
194
  def always_ok?
195
195
  usr_id = as_id
196
- return false if !usr_id
196
+ return false unless usr_id
197
197
  always_ok_usr_id? usr_id
198
198
  end
199
199
 
data/lib/card/cache.rb CHANGED
@@ -13,7 +13,7 @@ class Card
13
13
  end
14
14
 
15
15
  class Cache
16
- TEST_ENVS = %w{test cucumber}
16
+ TEST_ENVS = %w(test cucumber).freeze
17
17
  @@prepopulating = TEST_ENVS.include? Rails.env
18
18
  @@no_rails_cache = TEST_ENVS.include?(Rails.env) || ENV['NO_RAILS_CACHE']
19
19
  @@cache_by_class = {}
@@ -22,7 +22,7 @@ class Card
22
22
 
23
23
  class << self
24
24
  def [] klass
25
- fail 'nil klass' if klass.nil?
25
+ raise 'nil klass' if klass.nil?
26
26
  cache_type = (@@no_rails_cache ? nil : Cardio.cache)
27
27
  cache_by_class[klass] ||= new class: klass,
28
28
  store: cache_type
@@ -30,7 +30,7 @@ class Card
30
30
 
31
31
  def renew
32
32
  cache_by_class.keys do |klass|
33
- fail "renewing nil cache: #{klass}" unless klass.cache
33
+ raise "renewing nil cache: #{klass}" unless klass.cache
34
34
  cache_by_class[klass].system_prefix = system_prefix(klass)
35
35
  end
36
36
  reset_soft
@@ -136,7 +136,7 @@ class Card
136
136
  if @hard
137
137
  @hard.fetch(key, &block)
138
138
  else
139
- block.call
139
+ yield
140
140
  end
141
141
  end
142
142
  end
@@ -15,7 +15,7 @@ class Card::Cache::Persistent
15
15
  end
16
16
 
17
17
  def read key
18
- @store.read(@prefix + key)
18
+ @store.read(full_key(key))
19
19
  end
20
20
 
21
21
  def write_variable key, variable, value
@@ -27,15 +27,15 @@ class Card::Cache::Persistent
27
27
  end
28
28
 
29
29
  def write key, value
30
- @store.write(@prefix + key, value)
30
+ @store.write(full_key(key), value)
31
31
  end
32
32
 
33
33
  def fetch key, &block
34
- @store.fetch @prefix + key, &block
34
+ @store.fetch full_key(key), &block
35
35
  end
36
36
 
37
37
  def delete key
38
- @store.delete @prefix + key
38
+ @store.delete full_key(key)
39
39
  end
40
40
 
41
41
  def reset
@@ -45,6 +45,10 @@ class Card::Cache::Persistent
45
45
  end
46
46
 
47
47
  def exist? key
48
- @store.exist? @prefix + key
48
+ @store.exist? full_key(key)
49
+ end
50
+
51
+ def full_key key
52
+ @prefix + key
49
53
  end
50
54
  end
@@ -2,11 +2,11 @@ class Card::Cache::Temporary
2
2
  attr_reader :store
3
3
 
4
4
  def initialize
5
- @store = Hash.new
5
+ @store = {}
6
6
  end
7
7
 
8
8
  def read key
9
- return unless @store.has_key? key
9
+ return unless @store.key? key
10
10
  @store[key]
11
11
  end
12
12
 
@@ -14,8 +14,8 @@ class Card::Cache::Temporary
14
14
  @store[key] = value
15
15
  end
16
16
 
17
- def fetch key, &block
18
- read(key) || write(key, block.call)
17
+ def fetch key, &_block
18
+ read(key) || write(key, yield)
19
19
  end
20
20
 
21
21
  def delete key
@@ -33,6 +33,6 @@ class Card::Cache::Temporary
33
33
  end
34
34
 
35
35
  def exist? key
36
- @store.has_key? key
36
+ @store.key? key
37
37
  end
38
38
  end
data/lib/card/chunk.rb CHANGED
@@ -57,7 +57,7 @@ class Card
57
57
  :URI, :HostURI, :EmailURI, :EscapedLiteral, :Include, :Link
58
58
  ]
59
59
  register_list :references, [:EscapedLiteral, :Include, :Link]
60
- register_list :inclusion_only, [:Include]
60
+ register_list :nest_only, [:Include]
61
61
  register_list :query, [:QueryReference]
62
62
 
63
63
  class Abstract
data/lib/card/codename.rb CHANGED
@@ -43,7 +43,7 @@ class Card
43
43
 
44
44
  def check_duplicates codehash, codename, card_id
45
45
  # FIXME: remove duplicate checks here; should be caught upon creation
46
- return unless codehash.has_key?(codename) || codehash.has_key?(card_id)
46
+ return unless codehash.key?(codename) || codehash.key?(card_id)
47
47
  warn "dup code ID:#{card_id} (#{codehash[codename]}), " \
48
48
  "CD:#{codename} (#{codehash[card_id]})"
49
49
  end
@@ -63,7 +63,8 @@ class Card
63
63
  end
64
64
 
65
65
  def self.const_missing const
66
- if const.to_s =~ /^([A-Z]\S*)ID$/ && (code = $1.underscore.to_sym)
66
+ if const.to_s =~ /^([A-Z]\S*)ID$/ &&
67
+ (code = Regexp.last_match(1).underscore.to_sym)
67
68
  if (card_id = Codename[code])
68
69
  const_set const, card_id
69
70
  else
data/lib/card/content.rb CHANGED
@@ -16,9 +16,7 @@ class Card
16
16
  end
17
17
  @opts = opts || {}
18
18
 
19
- unless Array === content
20
- content = parse_content content
21
- end
19
+ content = parse_content content unless content.is_a?(Array)
22
20
  super content
23
21
  end
24
22
 
@@ -60,7 +58,7 @@ class Card
60
58
  end
61
59
 
62
60
  def process_each_chunk &block
63
- each_chunk { |chunk| chunk.process_chunk &block }
61
+ each_chunk { |chunk| chunk.process_chunk(&block) }
64
62
  self
65
63
  end
66
64
 
@@ -99,7 +97,7 @@ class Card
99
97
  position += (match.end(0) - offset.to_i)
100
98
  # move scanning position up to end of chunk
101
99
  if context_ok
102
- @chunks << interval_string if interval_string.size > 0
100
+ @chunks << interval_string unless interval_string.empty?
103
101
  # add the nonchunk string to the chunk list
104
102
  @chunks << chunk_class.new(match, self)
105
103
  # add the chunk to the chunk list
@@ -114,11 +112,10 @@ class Card
114
112
  # no match. look at the next character
115
113
  end
116
114
 
117
- if !match || !context_ok
118
- interval_string += content[chunk_start..position - 1]
119
- # moving beyond the alleged chunk.
120
- # append failed string to "nonchunk" string
121
- end
115
+ next unless !match || !context_ok
116
+ interval_string += content[chunk_start..position - 1]
117
+ # moving beyond the alleged chunk.
118
+ # append failed string to "nonchunk" string
122
119
  end
123
120
  end
124
121
 
@@ -135,21 +132,21 @@ class Card
135
132
  end
136
133
 
137
134
  ALLOWED_TAGS = {}
138
- %w{
135
+ %w(
139
136
  br i b pre cite caption strong em ins sup sub del ol hr ul li p
140
137
  div h1 h2 h3 h4 h5 h6 span table tr td th tbody thead tfoot
141
- }.each { |tag| ALLOWED_TAGS[tag] = [] }
138
+ ).each { |tag| ALLOWED_TAGS[tag] = [] }
142
139
 
143
140
  # allowed attributes
144
141
  ALLOWED_TAGS.merge!(
145
- 'a' => ['href', 'title', 'target'],
146
- 'img' => ['src', 'alt', 'title'],
142
+ 'a' => %w(href title target),
143
+ 'img' => %w(src alt title),
147
144
  'code' => ['lang'],
148
145
  'blockquote' => ['cite']
149
146
  )
150
147
 
151
148
  if Card.config.allow_inline_styles
152
- ALLOWED_TAGS['table'] += %w[ cellpadding align border cellspacing ]
149
+ ALLOWED_TAGS['table'] += %w( cellpadding align border cellspacing )
153
150
  end
154
151
 
155
152
  ALLOWED_TAGS.each_key do |k|
@@ -157,9 +154,9 @@ class Card
157
154
  ALLOWED_TAGS[k] << 'style' if Card.config.allow_inline_styles
158
155
  ALLOWED_TAGS[k]
159
156
  end
160
- ALLOWED_TAGS
157
+ ALLOWED_TAGS.freeze
161
158
 
162
- ATTR_VALUE_RE = [/(?<=^')[^']+(?=')/, /(?<=^")[^"]+(?=")/, /\S+/]
159
+ ATTR_VALUE_RE = [/(?<=^')[^']+(?=')/, /(?<=^")[^"]+(?=")/, /\S+/].freeze
163
160
 
164
161
  class << self
165
162
  ## Method that cleans the String of HTML tags
@@ -167,31 +164,15 @@ class Card
167
164
 
168
165
  # this has been hacked for card to allow classes if
169
166
  # the class begins with "w-"
170
- def clean!(string, tags=ALLOWED_TAGS)
171
- string.gsub(/<(\/*)(\w+)([^>]*)>/) do
172
- raw = $~
167
+ def clean! string, tags=ALLOWED_TAGS
168
+ string.gsub(%r{<(/*)(\w+)([^>]*)>}) do
169
+ raw = $LAST_MATCH_INFO
173
170
  tag = raw[2].downcase
174
171
  if (attrs = tags[tag])
175
172
  html_attribs =
176
- attrs.inject([tag]) do |pcs, attr|
177
- q = '"'
178
- rest_value = nil
179
- if raw[3] =~ /\b#{attr}\s*=\s*(?=(.))/i
180
- rest_value = $'
181
- (idx = %w{' "}.index($1)) && (q = $1)
182
- re = ATTR_VALUE_RE[idx || 2]
183
- if (match = rest_value.match(re))
184
- rest_value = match[0]
185
- if attr == 'class'
186
- rest_value =
187
- rest_value.split(/\s+/).select do |s|
188
- s =~ /^w-/i
189
- end * ' '
190
- end
191
- end
192
- end
173
+ attrs.each_with_object([tag]) do |attr, pcs|
174
+ q, rest_value = process_attribute attr, raw[3]
193
175
  pcs << "#{attr}=#{q}#{rest_value}#{q}" unless rest_value.blank?
194
- pcs
195
176
  end * ' '
196
177
  "<#{raw[1]}#{html_attribs}>"
197
178
  else
@@ -200,6 +181,23 @@ class Card
200
181
  end.gsub(/<\!--.*?-->/, '')
201
182
  end
202
183
 
184
+ def process_attribute attr, all_attributes
185
+ return ['"', nil] unless all_attributes =~ /\b#{attr}\s*=\s*(?=(.))/i
186
+ q = '"'
187
+ rest_value = $'
188
+ (idx = %w(' ").index(Regexp.last_match(1))) &&
189
+ (q = Regexp.last_match(1))
190
+ re = ATTR_VALUE_RE[idx || 2]
191
+ if (match = rest_value.match(re))
192
+ rest_value = match[0]
193
+ if attr == 'class'
194
+ rest_value =
195
+ rest_value.split(/\s+/).select { |s| s =~ /^w-/i }.join(' ')
196
+ end
197
+ end
198
+ [q, rest_value]
199
+ end
200
+
203
201
  if Card.config.space_last_in_multispace
204
202
  def clean_with_space_last! string, tags=ALLOWED_TAGS
205
203
  cwo = clean_without_space_last!(string, tags)
@@ -208,8 +206,9 @@ class Card
208
206
  alias_method_chain :clean!, :space_last
209
207
  end
210
208
 
211
- def truncatewords_with_closing_tags input, words=25, truncate_string='...'
212
- if input.nil? then return end
209
+ def truncatewords_with_closing_tags input, words=25,
210
+ _truncate_string='...'
211
+ return if input.nil?
213
212
  wordlist = input.to_s.split
214
213
  l = words.to_i - 1
215
214
  l = 0 if l < 0
@@ -217,21 +216,7 @@ class Card
217
216
  # nuke partial tags at end of snippet
218
217
  wordstring.gsub!(/(<[^\>]+)$/, '')
219
218
 
220
- tags = []
221
-
222
- # match tags with or without self closing (ie. <foo />)
223
- wordstring.scan(/\<([^\>\s\/]+)[^\>]*?\>/).each do |t|
224
- tags.unshift(t[0])
225
- end
226
- # match tags with self closing and mark them as closed
227
- wordstring.scan(/\<([^\>\s\/]+)[^\>]*?\/\>/).each do |t|
228
- if !(x = tags.index(t[0])).nil? then tags.slice!(x) end
229
- end
230
- # match close tags
231
- wordstring.scan(/\<\/([^\>\s\/]+)[^\>]*?\>/).each do |t|
232
- if !(x = tags.rindex(t[0])).nil? then tags.slice!(x) end
233
- end
234
-
219
+ tags = find_tags wordstring
235
220
  tags.each { |t| wordstring += "</#{t}>" }
236
221
 
237
222
  if wordlist.length > l
@@ -239,12 +224,32 @@ class Card
239
224
  end
240
225
 
241
226
  # wordstring += '...' if wordlist.length > l
242
- wordstring.gsub! /<[\/]?br[\s\/]*>/, ' '
227
+ wordstring.gsub! %r{<[/]?br[\s/]*>}, ' '
243
228
  # Also a hack -- get rid of <br>'s -- they make line view ugly.
244
- wordstring.gsub! /<[\/]?p[^>]*>/, ' '
229
+ wordstring.gsub! %r{<[/]?p[^>]*>}, ' '
245
230
  ## Also a hack -- get rid of <br>'s -- they make line view ugly.
246
231
  wordstring
247
232
  end
233
+
234
+ def find_tags wordstring
235
+ tags = []
236
+
237
+ # match tags with or without self closing (ie. <foo />)
238
+ wordstring.scan(%r{\<([^\>\s/]+)[^\>]*?\>}).each do |t|
239
+ tags.unshift(t[0])
240
+ end
241
+ # match tags with self closing and mark them as closed
242
+ wordstring.scan(%r{\<([^\>\s/]+)[^\>]*?/\>}).each do |t|
243
+ next unless (x = tags.index(t[0]))
244
+ tags.slice!(x)
245
+ end
246
+ # match close tags
247
+ wordstring.scan(%r{\</([^\>\s/]+)[^\>]*?\>}).each do |t|
248
+ next unless (x = tags.rindex(t[0]))
249
+ tags.slice!(x)
250
+ end
251
+ tags
252
+ end
248
253
  end
249
254
  end
250
255
  end