roda-component 0.1.11 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (307) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1 -1
  3. data/lib/roda/component.rb +107 -4
  4. data/lib/roda/component/dom.rb +9 -15
  5. data/lib/roda/component/events.rb +28 -7
  6. data/lib/roda/component/form.rb +126 -13
  7. data/lib/roda/component/form/validations.rb +18 -6
  8. data/lib/roda/component/titleize.rb +97 -0
  9. data/lib/roda/component/version.rb +1 -1
  10. data/test/dummy/.bowerrc +1 -1
  11. data/test/dummy/app.rb +31 -13
  12. data/test/dummy/bower.json +1 -1
  13. data/test/dummy/components/form.rb +46 -0
  14. data/test/dummy/components/forms/address.rb +11 -0
  15. data/test/dummy/components/forms/form.rb +14 -0
  16. data/test/dummy/components/layout.rb +2 -2
  17. data/test/dummy/components/login.rb +6 -6
  18. data/test/dummy/config.ru +1 -14
  19. data/test/dummy/dummy.db +0 -0
  20. data/test/dummy/models/user.rb +15 -13
  21. data/test/dummy/public/{chat/bower → bower}/font-awesome/.bower.json +0 -0
  22. data/test/dummy/public/{chat/bower → bower}/font-awesome/.gitignore +0 -0
  23. data/test/dummy/public/{chat/bower → bower}/font-awesome/.npmignore +0 -0
  24. data/test/dummy/public/{chat/bower → bower}/font-awesome/bower.json +0 -0
  25. data/test/dummy/public/{chat/bower → bower}/font-awesome/css/font-awesome.css +0 -0
  26. data/test/dummy/public/{chat/bower → bower}/font-awesome/css/font-awesome.min.css +0 -0
  27. data/test/dummy/public/{chat/bower → bower}/font-awesome/fonts/FontAwesome.otf +0 -0
  28. data/test/dummy/public/{chat/bower → bower}/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  29. data/test/dummy/public/{chat/bower → bower}/font-awesome/fonts/fontawesome-webfont.svg +0 -0
  30. data/test/dummy/public/{chat/bower → bower}/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  31. data/test/dummy/public/{chat/bower → bower}/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  32. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/bordered-pulled.less +0 -0
  33. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/core.less +0 -0
  34. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/extras.less +0 -0
  35. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/fixed-width.less +0 -0
  36. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/font-awesome.less +0 -0
  37. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/icons.less +0 -0
  38. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/larger.less +0 -0
  39. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/list.less +0 -0
  40. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/mixins.less +0 -0
  41. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/path.less +0 -0
  42. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/rotated-flipped.less +0 -0
  43. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/spinning.less +0 -0
  44. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/stacked.less +0 -0
  45. data/test/dummy/public/{chat/bower → bower}/font-awesome/less/variables.less +0 -0
  46. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_bordered-pulled.scss +0 -0
  47. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_core.scss +0 -0
  48. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_extras.scss +0 -0
  49. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_fixed-width.scss +0 -0
  50. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_icons.scss +0 -0
  51. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_larger.scss +0 -0
  52. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_list.scss +0 -0
  53. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_mixins.scss +0 -0
  54. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_path.scss +0 -0
  55. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_rotated-flipped.scss +0 -0
  56. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_spinning.scss +0 -0
  57. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_stacked.scss +0 -0
  58. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/_variables.scss +0 -0
  59. data/test/dummy/public/{chat/bower → bower}/font-awesome/scss/font-awesome.scss +0 -0
  60. data/test/dummy/public/{chat/bower → bower}/jScrollPane/.bower.json +0 -0
  61. data/test/dummy/public/{chat/bower → bower}/jScrollPane/.gitignore +0 -0
  62. data/test/dummy/public/{chat/bower → bower}/jScrollPane/.gitmodules +0 -0
  63. data/test/dummy/public/{chat/bower → bower}/jScrollPane/GPL-LICENSE.txt +0 -0
  64. data/test/dummy/public/{chat/bower → bower}/jScrollPane/MIT-LICENSE.txt +0 -0
  65. data/test/dummy/public/{chat/bower → bower}/jScrollPane/README.md +0 -0
  66. data/test/dummy/public/{chat/bower → bower}/jScrollPane/ajax.html +0 -0
  67. data/test/dummy/public/{chat/bower → bower}/jScrollPane/ajax_content.html +0 -0
  68. data/test/dummy/public/{chat/bower → bower}/jScrollPane/anchors.html +0 -0
  69. data/test/dummy/public/{chat/bower → bower}/jScrollPane/api.html +0 -0
  70. data/test/dummy/public/{chat/bower → bower}/jScrollPane/arrow_hover.html +0 -0
  71. data/test/dummy/public/{chat/bower → bower}/jScrollPane/arrow_positions.html +0 -0
  72. data/test/dummy/public/{chat/bower → bower}/jScrollPane/arrows.html +0 -0
  73. data/test/dummy/public/{chat/bower → bower}/jScrollPane/auto_reinitialise.html +0 -0
  74. data/test/dummy/public/{chat/bower → bower}/jScrollPane/basic.html +0 -0
  75. data/test/dummy/public/{chat/bower → bower}/jScrollPane/bower.json +0 -0
  76. data/test/dummy/public/{chat/bower → bower}/jScrollPane/build/.gitignore +0 -0
  77. data/test/dummy/public/{chat/bower → bower}/jScrollPane/build/Gruntfile.js +0 -0
  78. data/test/dummy/public/{chat/bower → bower}/jScrollPane/build/package.json +0 -0
  79. data/test/dummy/public/{chat/bower → bower}/jScrollPane/caps.html +0 -0
  80. data/test/dummy/public/{chat/bower → bower}/jScrollPane/changelog.html +0 -0
  81. data/test/dummy/public/{chat/bower → bower}/jScrollPane/destroy.html +0 -0
  82. data/test/dummy/public/{chat/bower → bower}/jScrollPane/drag_size.html +0 -0
  83. data/test/dummy/public/{chat/bower → bower}/jScrollPane/dynamic_content.html +0 -0
  84. data/test/dummy/public/{chat/bower → bower}/jScrollPane/dynamic_height.html +0 -0
  85. data/test/dummy/public/{chat/bower → bower}/jScrollPane/dynamic_width.html +0 -0
  86. data/test/dummy/public/{chat/bower → bower}/jScrollPane/events.html +0 -0
  87. data/test/dummy/public/{chat/bower → bower}/jScrollPane/faqs.html +0 -0
  88. data/test/dummy/public/{chat/bower → bower}/jScrollPane/fixed_width.html +0 -0
  89. data/test/dummy/public/{chat/bower → bower}/jScrollPane/focus.html +0 -0
  90. data/test/dummy/public/{chat/bower → bower}/jScrollPane/fullpage_scroll.html +0 -0
  91. data/test/dummy/public/{chat/bower → bower}/jScrollPane/iframe.html +0 -0
  92. data/test/dummy/public/{chat/bower → bower}/jScrollPane/iframe2.html +0 -0
  93. data/test/dummy/public/{chat/bower → bower}/jScrollPane/iframe_content1.html +0 -0
  94. data/test/dummy/public/{chat/bower → bower}/jScrollPane/iframe_content2.html +0 -0
  95. data/test/dummy/public/{chat/bower → bower}/jScrollPane/iframe_content3.html +0 -0
  96. data/test/dummy/public/{chat/bower → bower}/jScrollPane/iframe_content4.html +0 -0
  97. data/test/dummy/public/{chat/bower → bower}/jScrollPane/image.html +0 -0
  98. data/test/dummy/public/{chat/bower → bower}/jScrollPane/image/logo.png +0 -0
  99. data/test/dummy/public/{chat/bower → bower}/jScrollPane/image2.html +0 -0
  100. data/test/dummy/public/{chat/bower → bower}/jScrollPane/index.html +0 -0
  101. data/test/dummy/public/{chat/bower → bower}/jScrollPane/invisibles.html +0 -0
  102. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/after.html +0 -0
  103. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/before.html +0 -0
  104. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/brs_main.css +0 -0
  105. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/index.html +0 -0
  106. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/jquery.mousewheel.js +0 -0
  107. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/jscrollpane-2b3.css +0 -0
  108. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/jscrollpane-2b3.js +0 -0
  109. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/11/native.html +0 -0
  110. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/after.html +0 -0
  111. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/after_reinit.html +0 -0
  112. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/before.html +0 -0
  113. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/before_reinit.html +0 -0
  114. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/brs_main.css +0 -0
  115. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/index.html +0 -0
  116. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/jquery.mousewheel.js +0 -0
  117. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/jscrollpane-2b3.css +0 -0
  118. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/jscrollpane-2b3.js +0 -0
  119. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/native.html +0 -0
  120. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/12/wrapped.html +0 -0
  121. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/7/after.html +0 -0
  122. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/7/before.html +0 -0
  123. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/7/index.html +0 -0
  124. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/7/jscrollpane-2b1.css +0 -0
  125. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/7/jscrollpane-2b2.js +0 -0
  126. data/test/dummy/public/{chat/bower → bower}/jScrollPane/issues/7/native.html +0 -0
  127. data/test/dummy/public/{chat/bower → bower}/jScrollPane/known_issues.html +0 -0
  128. data/test/dummy/public/{chat/bower → bower}/jScrollPane/less_basic.html +0 -0
  129. data/test/dummy/public/{chat/bower → bower}/jScrollPane/mwheel_intent.html +0 -0
  130. data/test/dummy/public/{chat/bower → bower}/jScrollPane/override_animate.html +0 -0
  131. data/test/dummy/public/{chat/bower → bower}/jScrollPane/runeimp.html +0 -0
  132. data/test/dummy/public/{chat/bower → bower}/jScrollPane/runeimp2.html +0 -0
  133. data/test/dummy/public/{chat/bower → bower}/jScrollPane/script/demo.js +0 -0
  134. data/test/dummy/public/{chat/bower → bower}/jScrollPane/script/jquery.jscrollpane.js +0 -0
  135. data/test/dummy/public/{chat/bower → bower}/jScrollPane/script/jquery.jscrollpane.min.js +0 -0
  136. data/test/dummy/public/{chat/bower → bower}/jScrollPane/script/jquery.mousewheel.js +0 -0
  137. data/test/dummy/public/{chat/bower → bower}/jScrollPane/script/mwheelIntent.js +0 -0
  138. data/test/dummy/public/{chat/bower → bower}/jScrollPane/scroll_on_left.html +0 -0
  139. data/test/dummy/public/{chat/bower → bower}/jScrollPane/scroll_to.html +0 -0
  140. data/test/dummy/public/{chat/bower → bower}/jScrollPane/scroll_to_animate.html +0 -0
  141. data/test/dummy/public/{chat/bower → bower}/jScrollPane/settings.html +0 -0
  142. data/test/dummy/public/{chat/bower → bower}/jScrollPane/short.html +0 -0
  143. data/test/dummy/public/{chat/bower → bower}/jScrollPane/style/demo.css +0 -0
  144. data/test/dummy/public/{chat/bower → bower}/jScrollPane/style/jquery.jscrollpane.css +0 -0
  145. data/test/dummy/public/{chat/bower → bower}/jScrollPane/themes/lozenge/image/ui-icons_222222_256x240.png +0 -0
  146. data/test/dummy/public/{chat/bower → bower}/jScrollPane/themes/lozenge/image/ui-icons_888888_256x240.png +0 -0
  147. data/test/dummy/public/{chat/bower → bower}/jScrollPane/themes/lozenge/image/ui-icons_cd0a0a_256x240.png +0 -0
  148. data/test/dummy/public/{chat/bower → bower}/jScrollPane/themes/lozenge/index.html +0 -0
  149. data/test/dummy/public/{chat/bower → bower}/jScrollPane/themes/lozenge/style/jquery.jscrollpane.lozenge.css +0 -0
  150. data/test/dummy/public/{chat/bower → bower}/jScrollPane/v1.html +0 -0
  151. data/test/dummy/public/{chat/bower → bower}/jquery/.bower.json +0 -0
  152. data/test/dummy/public/{chat/bower → bower}/jquery/MIT-LICENSE.txt +0 -0
  153. data/test/dummy/public/{chat/bower → bower}/jquery/bower.json +0 -0
  154. data/test/dummy/public/{chat/bower → bower}/jquery/dist/jquery.js +0 -0
  155. data/test/dummy/public/{chat/bower → bower}/jquery/dist/jquery.min.js +0 -0
  156. data/test/dummy/public/{chat/bower → bower}/jquery/dist/jquery.min.map +0 -0
  157. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax.js +0 -0
  158. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/jsonp.js +0 -0
  159. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/load.js +0 -0
  160. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/parseJSON.js +0 -0
  161. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/parseXML.js +0 -0
  162. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/script.js +0 -0
  163. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/var/nonce.js +0 -0
  164. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/var/rquery.js +0 -0
  165. data/test/dummy/public/{chat/bower → bower}/jquery/src/ajax/xhr.js +0 -0
  166. data/test/dummy/public/{chat/bower → bower}/jquery/src/attributes.js +0 -0
  167. data/test/dummy/public/{chat/bower → bower}/jquery/src/attributes/attr.js +0 -0
  168. data/test/dummy/public/{chat/bower → bower}/jquery/src/attributes/classes.js +0 -0
  169. data/test/dummy/public/{chat/bower → bower}/jquery/src/attributes/prop.js +0 -0
  170. data/test/dummy/public/{chat/bower → bower}/jquery/src/attributes/support.js +0 -0
  171. data/test/dummy/public/{chat/bower → bower}/jquery/src/attributes/val.js +0 -0
  172. data/test/dummy/public/{chat/bower → bower}/jquery/src/callbacks.js +0 -0
  173. data/test/dummy/public/{chat/bower → bower}/jquery/src/core.js +0 -0
  174. data/test/dummy/public/{chat/bower → bower}/jquery/src/core/access.js +0 -0
  175. data/test/dummy/public/{chat/bower → bower}/jquery/src/core/init.js +0 -0
  176. data/test/dummy/public/{chat/bower → bower}/jquery/src/core/parseHTML.js +0 -0
  177. data/test/dummy/public/{chat/bower → bower}/jquery/src/core/ready.js +0 -0
  178. data/test/dummy/public/{chat/bower → bower}/jquery/src/core/var/rsingleTag.js +0 -0
  179. data/test/dummy/public/{chat/bower → bower}/jquery/src/css.js +0 -0
  180. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/addGetHookIf.js +0 -0
  181. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/curCSS.js +0 -0
  182. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/defaultDisplay.js +0 -0
  183. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/hiddenVisibleSelectors.js +0 -0
  184. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/support.js +0 -0
  185. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/swap.js +0 -0
  186. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/var/cssExpand.js +0 -0
  187. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/var/getStyles.js +0 -0
  188. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/var/isHidden.js +0 -0
  189. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/var/rmargin.js +0 -0
  190. data/test/dummy/public/{chat/bower → bower}/jquery/src/css/var/rnumnonpx.js +0 -0
  191. data/test/dummy/public/{chat/bower → bower}/jquery/src/data.js +0 -0
  192. data/test/dummy/public/{chat/bower → bower}/jquery/src/data/Data.js +0 -0
  193. data/test/dummy/public/{chat/bower → bower}/jquery/src/data/accepts.js +0 -0
  194. data/test/dummy/public/{chat/bower → bower}/jquery/src/data/var/data_priv.js +0 -0
  195. data/test/dummy/public/{chat/bower → bower}/jquery/src/data/var/data_user.js +0 -0
  196. data/test/dummy/public/{chat/bower → bower}/jquery/src/deferred.js +0 -0
  197. data/test/dummy/public/{chat/bower → bower}/jquery/src/deprecated.js +0 -0
  198. data/test/dummy/public/{chat/bower → bower}/jquery/src/dimensions.js +0 -0
  199. data/test/dummy/public/{chat/bower → bower}/jquery/src/effects.js +0 -0
  200. data/test/dummy/public/{chat/bower → bower}/jquery/src/effects/Tween.js +0 -0
  201. data/test/dummy/public/{chat/bower → bower}/jquery/src/effects/animatedSelector.js +0 -0
  202. data/test/dummy/public/{chat/bower → bower}/jquery/src/event.js +0 -0
  203. data/test/dummy/public/{chat/bower → bower}/jquery/src/event/ajax.js +0 -0
  204. data/test/dummy/public/{chat/bower → bower}/jquery/src/event/alias.js +0 -0
  205. data/test/dummy/public/{chat/bower → bower}/jquery/src/event/support.js +0 -0
  206. data/test/dummy/public/{chat/bower → bower}/jquery/src/exports/amd.js +0 -0
  207. data/test/dummy/public/{chat/bower → bower}/jquery/src/exports/global.js +0 -0
  208. data/test/dummy/public/{chat/bower → bower}/jquery/src/intro.js +0 -0
  209. data/test/dummy/public/{chat/bower → bower}/jquery/src/jquery.js +0 -0
  210. data/test/dummy/public/{chat/bower → bower}/jquery/src/manipulation.js +0 -0
  211. data/test/dummy/public/{chat/bower → bower}/jquery/src/manipulation/_evalUrl.js +0 -0
  212. data/test/dummy/public/{chat/bower → bower}/jquery/src/manipulation/support.js +0 -0
  213. data/test/dummy/public/{chat/bower → bower}/jquery/src/manipulation/var/rcheckableType.js +0 -0
  214. data/test/dummy/public/{chat/bower → bower}/jquery/src/offset.js +0 -0
  215. data/test/dummy/public/{chat/bower → bower}/jquery/src/outro.js +0 -0
  216. data/test/dummy/public/{chat/bower → bower}/jquery/src/queue.js +0 -0
  217. data/test/dummy/public/{chat/bower → bower}/jquery/src/queue/delay.js +0 -0
  218. data/test/dummy/public/{chat/bower → bower}/jquery/src/selector-native.js +0 -0
  219. data/test/dummy/public/{chat/bower → bower}/jquery/src/selector-sizzle.js +0 -0
  220. data/test/dummy/public/{chat/bower → bower}/jquery/src/selector.js +0 -0
  221. data/test/dummy/public/{chat/bower → bower}/jquery/src/serialize.js +0 -0
  222. data/test/dummy/public/{chat/bower → bower}/jquery/src/sizzle/dist/sizzle.js +0 -0
  223. data/test/dummy/public/{chat/bower → bower}/jquery/src/sizzle/dist/sizzle.min.js +0 -0
  224. data/test/dummy/public/{chat/bower → bower}/jquery/src/sizzle/dist/sizzle.min.map +0 -0
  225. data/test/dummy/public/{chat/bower → bower}/jquery/src/traversing.js +0 -0
  226. data/test/dummy/public/{chat/bower → bower}/jquery/src/traversing/findFilter.js +0 -0
  227. data/test/dummy/public/{chat/bower → bower}/jquery/src/traversing/var/rneedsContext.js +0 -0
  228. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/arr.js +0 -0
  229. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/class2type.js +0 -0
  230. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/concat.js +0 -0
  231. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/hasOwn.js +0 -0
  232. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/indexOf.js +0 -0
  233. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/pnum.js +0 -0
  234. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/push.js +0 -0
  235. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/rnotwhite.js +0 -0
  236. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/slice.js +0 -0
  237. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/strundefined.js +0 -0
  238. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/support.js +0 -0
  239. data/test/dummy/public/{chat/bower → bower}/jquery/src/var/toString.js +0 -0
  240. data/test/dummy/public/{chat/bower → bower}/jquery/src/wrap.js +0 -0
  241. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/.bower.json +0 -0
  242. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/README.md +0 -0
  243. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/bower.json +0 -0
  244. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Bold/OpenSans-Bold.eot +0 -0
  245. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Bold/OpenSans-Bold.svg +0 -0
  246. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Bold/OpenSans-Bold.ttf +0 -0
  247. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Bold/OpenSans-Bold.woff +0 -0
  248. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/BoldItalic/OpenSans-BoldItalic.eot +0 -0
  249. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/BoldItalic/OpenSans-BoldItalic.svg +0 -0
  250. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/BoldItalic/OpenSans-BoldItalic.ttf +0 -0
  251. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/BoldItalic/OpenSans-BoldItalic.woff +0 -0
  252. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBold/OpenSans-ExtraBold.eot +0 -0
  253. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBold/OpenSans-ExtraBold.svg +0 -0
  254. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBold/OpenSans-ExtraBold.ttf +0 -0
  255. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBold/OpenSans-ExtraBold.woff +0 -0
  256. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.eot +0 -0
  257. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.svg +0 -0
  258. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.ttf +0 -0
  259. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff +0 -0
  260. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Italic/OpenSans-Italic.eot +0 -0
  261. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Italic/OpenSans-Italic.svg +0 -0
  262. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Italic/OpenSans-Italic.ttf +0 -0
  263. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Italic/OpenSans-Italic.woff +0 -0
  264. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Light/OpenSans-Light.eot +0 -0
  265. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Light/OpenSans-Light.svg +0 -0
  266. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Light/OpenSans-Light.ttf +0 -0
  267. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Light/OpenSans-Light.woff +0 -0
  268. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/LightItalic/OpenSans-LightItalic.eot +0 -0
  269. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/LightItalic/OpenSans-LightItalic.svg +0 -0
  270. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/LightItalic/OpenSans-LightItalic.ttf +0 -0
  271. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/LightItalic/OpenSans-LightItalic.woff +0 -0
  272. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Regular/OpenSans-Regular.eot +0 -0
  273. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Regular/OpenSans-Regular.svg +0 -0
  274. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Regular/OpenSans-Regular.ttf +0 -0
  275. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Regular/OpenSans-Regular.woff +0 -0
  276. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Semibold/OpenSans-Semibold.eot +0 -0
  277. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Semibold/OpenSans-Semibold.svg +0 -0
  278. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Semibold/OpenSans-Semibold.ttf +0 -0
  279. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/Semibold/OpenSans-Semibold.woff +0 -0
  280. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/SemiboldItalic/OpenSans-SemiboldItalic.eot +0 -0
  281. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/SemiboldItalic/OpenSans-SemiboldItalic.svg +0 -0
  282. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/SemiboldItalic/OpenSans-SemiboldItalic.ttf +0 -0
  283. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/fonts/SemiboldItalic/OpenSans-SemiboldItalic.woff +0 -0
  284. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/index.html +0 -0
  285. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/open-sans.css +0 -0
  286. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/open-sans.less +0 -0
  287. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/open-sans.scss +0 -0
  288. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/package.json +0 -0
  289. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_Bold.scss +0 -0
  290. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_BoldItalic.scss +0 -0
  291. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_ExtraBold.scss +0 -0
  292. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_ExtraBoldItalic.scss +0 -0
  293. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_Italic.scss +0 -0
  294. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_Light.scss +0 -0
  295. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_LightItalic.scss +0 -0
  296. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_Regular.scss +0 -0
  297. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_Semibold.scss +0 -0
  298. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_SemiboldItalic.scss +0 -0
  299. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_mixins.scss +0 -0
  300. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/_variables.scss +0 -0
  301. data/test/dummy/public/{chat/bower → bower}/open-sans-fontface/sass/open-sans.scss +0 -0
  302. data/test/dummy/public/form/README.txt +7 -0
  303. data/test/dummy/public/form/css/style.css +80 -0
  304. data/test/dummy/public/form/index.html +58 -0
  305. data/test/dummy/public/form/js/index.js +24 -0
  306. data/test/dummy/public/form/license.txt +9 -0
  307. metadata +579 -564
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f4a5eae005846dcc62d4f857ab356a2c4e84d7d
4
- data.tar.gz: 553ff76fca4ffce5052fc99a70a5a707e7b92da3
3
+ metadata.gz: c34cd225e507b714d1ed28cbcd790594ed9f1c6d
4
+ data.tar.gz: 573d2e494f92e75cd8fd5eaa78045258c604c738
5
5
  SHA512:
6
- metadata.gz: 3b03cb1ec47537a9eda3f27575e0a39a340015da850a6721e7204962c647a98a181c70b31904096218deac5c917ec7b623ebc6fcffab991263211fd402ef3322
7
- data.tar.gz: 6ccf36087e6be7d7e6ba42a8a8a614a6f0d5dee55cf492025bc23fc27b7f2922fe3cf68f5d305a7604f5a7dfca576a4c244b21fe1719314b29fb1098c6f896eb
6
+ metadata.gz: 24abc995392ede94e7dbc120d2f4ae0f67999456c2bee8f963cb3c822fa1487cd21cbca2d0c2646208bcc2c8210ad19ad87ca64bebc1b5a282d7073a20d52495
7
+ data.tar.gz: f7b60008671dce4daa71c1dedacbd74daa2cf727df68cf0b26ee27dfb31d99f0f3b962e68a2190f9e29ae1b7ad8a4d5f75b584a51a93f2e65a6040b0921a3f95
data/Makefile CHANGED
@@ -22,7 +22,7 @@ install:
22
22
  server:
23
23
  bundle
24
24
  # cd test/dummy && touch dummy.db && rm dummy.db && bundle exec thin start -p 8080
25
- cd test/dummy && touch dummy.db && bundle exec thin start -p 8080
25
+ cd test/dummy && touch dummy.db && bundle exec roda server
26
26
 
27
27
  test:
28
28
  bundle exec pry-test --async
@@ -3,10 +3,6 @@ require 'opal-jquery'
3
3
 
4
4
  unless RUBY_ENGINE == 'opal'
5
5
  require 'tilt'
6
-
7
- if defined? Oga
8
- require 'roda/component/oga'
9
- end
10
6
  end
11
7
 
12
8
  require "base64"
@@ -14,6 +10,7 @@ require 'roda/component/faye'
14
10
  require 'roda/component/instance'
15
11
  require 'roda/component/dom'
16
12
  require 'roda/component/events'
13
+ require 'roda/component/titleize'
17
14
 
18
15
  if RUBY_ENGINE == 'opal'
19
16
  require 'roda/component/element'
@@ -27,6 +24,28 @@ if RUBY_ENGINE == 'opal'
27
24
  end
28
25
 
29
26
  class Roda
27
+ class ::Hash
28
+ # add keys to hash
29
+ def to_obj
30
+ self.each do |k,v|
31
+ if v.kind_of? Hash
32
+ v.to_obj
33
+ end
34
+ k=k.to_s.gsub(/\.|\s|-|\/|\'/, '_').downcase.to_sym
35
+
36
+ ## create and initialize an instance variable for this key/value pair
37
+ self.instance_variable_set("@#{k}", v)
38
+
39
+ ## create the getter that returns the instance variable
40
+ self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
41
+
42
+ ## create the setter that sets the instance variable
43
+ self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
44
+ end
45
+ return self
46
+ end
47
+ end
48
+
30
49
  class Component
31
50
  attr_accessor :scope, :cache
32
51
 
@@ -282,6 +301,90 @@ class Roda
282
301
  end
283
302
  end
284
303
 
304
+ def render_fields data, options = {}
305
+ data = data.is_a?(Hash) ? data.to_obj : data
306
+
307
+ l_dom = options[:dom] || dom
308
+
309
+ l_dom.find("[data-if]") do |field_dom|
310
+ value = get_value_for field_dom['data-if'], data
311
+
312
+ unless value
313
+ field_dom.remove
314
+ end
315
+ end
316
+
317
+ l_dom.find("[data-unless]") do |field_dom|
318
+ value = get_value_for field_dom['data-unless'], data
319
+
320
+ if value
321
+ field_dom.remove
322
+ end
323
+ end
324
+
325
+ l_dom.find("[data-field]") do |field_dom|
326
+ if field = field_dom['data-field']
327
+ value = get_value_for field, data
328
+
329
+ if !value.nil?
330
+ value = value.to_s
331
+
332
+ if value != value.upcase && !value.match(Roda::Component::Form::EMAIL)
333
+ field_value = value.titleize
334
+ else
335
+ field_value = value
336
+ end
337
+
338
+ field_value = 'No' if field_value == 'False'
339
+ field_value = 'Yes' if field_value == 'True'
340
+
341
+ field_dom.html = field_value
342
+ else
343
+ field_dom.html = ''
344
+ end
345
+ end
346
+ end
347
+ end
348
+
349
+ def get_value_for field, data
350
+ field = (field || '').split '.'
351
+
352
+ if field.length > 1
353
+ value = data.is_a?(Hash) ? data.to_obj : data
354
+
355
+ field.each_with_index do |f, i|
356
+ # might not have the parent object
357
+ unless !value.empty?
358
+ value = ''
359
+ next
360
+ end
361
+
362
+ if (i+1) < field.length
363
+ begin
364
+ value = value.send(f)
365
+ rescue
366
+ value = nil
367
+ end
368
+ else
369
+ begin
370
+ value = value.respond_to?(:present) ? value.present("print_#{f}") : value.send(f)
371
+ rescue
372
+ value = nil
373
+ end
374
+ end
375
+
376
+ end
377
+ else
378
+ begin
379
+ value = data.respond_to?(:present) ? data.present("print_#{field.first}") : data.send(field.first)
380
+ rescue
381
+ value = nil
382
+ end
383
+ end
384
+
385
+ value
386
+ end
387
+
285
388
  private
286
389
 
287
390
  def server?
@@ -7,7 +7,7 @@ class Roda
7
7
  @raw_html = html
8
8
 
9
9
  if server?
10
- @dom = Component::HTML(raw_html)
10
+ @dom = raw_html.is_a?(String) ? Component::HTML(raw_html): raw_html
11
11
  else
12
12
  @dom = raw_html.is_a?(String) ? Element[raw_html] : raw_html
13
13
  end
@@ -15,30 +15,24 @@ class Roda
15
15
 
16
16
  def find string, &block
17
17
  if server?
18
- @node = dom.css string
18
+ @node = dom.css(string)
19
19
  else
20
- @node = dom.find string
20
+ @node = dom.find(string)
21
21
  end
22
22
 
23
23
  if block
24
- if server?
25
- node.each do |n|
26
- block.call n
27
- end
28
- else
29
- block.call node
24
+ node.each do |n|
25
+ block.call DOM.new n
30
26
  end
31
27
  else
32
28
  if server?
33
- @node = node.first
29
+ @node = DOM.new node.first
30
+ else
31
+ @node = DOM.new node
34
32
  end
35
33
  end
36
34
 
37
- if server?
38
- self
39
- else
40
- node
41
- end
35
+ node
42
36
  end
43
37
 
44
38
  def html= content
@@ -1,12 +1,19 @@
1
1
  class Roda
2
2
  class Component
3
+ class ::Hash
4
+ def deep_merge(second)
5
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
6
+ self.merge(second, &merger)
7
+ end
8
+ end
9
+
3
10
  class Events < Struct.new(:klass, :component_opts, :scope, :request)
4
- def on name, options = {}, extra_opts = false, &block
11
+ def on name, options = {}, form_klass = false, extra_opts = false, &block
5
12
  if client? && options.is_a?(String)
6
13
  class_name = klass._name
7
14
  class_events = (events[class_name] ||= {})
8
15
  event = (class_events[:_jquery_events] ||= [])
9
- event << [block, class_name, options, extra_opts, name]
16
+ event << [block, class_name, options, form_klass, extra_opts, name]
10
17
  elsif options.is_a?(Hash)
11
18
  limit_if = options.delete(:if) || []
12
19
  limit_if = [limit_if] unless limit_if.is_a? Array
@@ -28,7 +35,9 @@ class Roda
28
35
  return unless e = events[klass._name]
29
36
 
30
37
  (e[:_jquery_events] || []).each do |event|
31
- block, comp, selector, opts, name = event
38
+ block, comp, selector, form_klass, opts, name = event
39
+
40
+ opts = {} unless opts
32
41
 
33
42
  name = name.to_s
34
43
 
@@ -38,10 +47,9 @@ class Roda
38
47
 
39
48
  Component::Instance.new(component(comp), scope).instance_exec el, &block
40
49
  when 'form'
41
- klass = opts.delete :class
42
- warn 'missing form class option' unless klass
50
+ warn 'missing form class option' unless form_klass
43
51
 
44
- el = DOM.new Element.find(selector)
52
+ el = Element.find(selector)
45
53
 
46
54
  el.on :submit do |evt|
47
55
  evt.prevent_default
@@ -61,7 +69,20 @@ class Roda
61
69
  params[name] = value
62
70
  end
63
71
 
64
- form = klass.new params, dom: el
72
+ params_obj = {}
73
+
74
+ params.each do |param, value|
75
+ keys = param.gsub(/[^a-z0-9_]/, '|').gsub(/\|\|/, '|').gsub(/\|$/, '').split('|')
76
+ params_obj = params_obj.deep_merge keys.reverse.inject(value) { |a, n| { n => a } }
77
+ end
78
+
79
+ opts[:dom] = el
80
+
81
+ if opts && key = opts[:key]
82
+ form = form_klass.new params_obj[key], opts
83
+ else
84
+ form = form_klass.new params_obj, opts
85
+ end
65
86
 
66
87
  Component::Instance.new(component(comp), scope).instance_exec form, evt.current_target, evt, &block
67
88
  end
@@ -5,6 +5,38 @@ class Roda
5
5
  class Form
6
6
  include Validations
7
7
 
8
+ class Attributes
9
+ def set_values(atts)
10
+ @_attributes = []
11
+
12
+ atts.each do |key, val|
13
+ send(:"#{key}=", val)
14
+ @_attributes << key
15
+ end
16
+ end
17
+
18
+ def set_attr_accessors attrs
19
+ attrs.each do |attr|
20
+ define_singleton_method "#{attr}=" do |value|
21
+ value = value.to_obj if value.is_a? Hash
22
+ instance_variable_set(:"@#{attr}", value)
23
+ end
24
+
25
+ define_singleton_method attr do
26
+ instance_variable_get(:"@#{attr}")
27
+ end
28
+ end
29
+ end
30
+
31
+ def _attributes
32
+ @_attributes ||= []
33
+ end
34
+
35
+ def empty?
36
+ _attributes.empty?
37
+ end
38
+ end
39
+
8
40
  # Initialize with a hash of attributes and values.
9
41
  # If extra attributes are sent, a NoMethodError exception will be raised.
10
42
  #
@@ -37,20 +69,35 @@ class Roda
37
69
  def initialize(atts, options = {})
38
70
  @_options = options
39
71
 
40
- atts.each do |key, val|
41
- send(:"#{key}=", val)
72
+ # @_attributes = Class.new(Attributes).new
73
+ @_attributes = Attributes.new
74
+ @_attributes.set_attr_accessors _attr_accessors
75
+ @_attributes.set_values atts
76
+ end
77
+
78
+ def self.attr_accessor(*vars)
79
+ @_attr_accessors ||= []
80
+ @_attr_accessors.concat vars
81
+ end
82
+
83
+ def method_missing method, *args, &block
84
+ # respond_to?(symbol, include_all=false)
85
+ if _attributes.respond_to? method, true
86
+ _attributes.send method, *args, &block
87
+ else
88
+ super
42
89
  end
43
90
  end
44
91
 
45
92
  # Return hash of attributes and values.
46
93
  def attributes
47
94
  Hash.new.tap do |atts|
48
- instance_variables.each do |ivar|
95
+ _attributes.instance_variables.each do |ivar|
49
96
  # todo: figure out why it's setting @constructor and @toString
50
- next if ivar == :@errors || ivar == :@_options || ivar == :@_dom || ivar == :@constructor || ivar == :@toString
97
+ next if ivar == :@constructor || ivar == :@toString || ivar == :@_attributes
51
98
 
52
99
  att = ivar[1..-1].to_sym
53
- atts[att] = send(att)
100
+ atts[att] = _attributes.send(att)
54
101
  end
55
102
  end
56
103
  end
@@ -58,31 +105,93 @@ class Roda
58
105
  def slice(*keys)
59
106
  Hash.new.tap do |atts|
60
107
  keys.each do |att|
61
- atts[att] = send(att)
108
+ atts[att] = _attributes.send(att)
62
109
  end
63
110
  end
64
111
  end
65
112
 
66
113
  def display_errors options = {}
114
+ d_errors = errors
115
+
116
+ if override_errors = options[:override_errors]
117
+ d_errors = override_errors
118
+ end
119
+
120
+ keys = options.delete(:keys) || (_options[:key] ? [_options[:key]] : [])
121
+
67
122
  if extra_errors = options.delete(:errors)
68
123
  extra_errors.each do |key, value|
69
- errors[key] = value
124
+ d_errors[key] = value
70
125
  end
71
126
  end
72
127
 
73
- errors.each do |key, error|
128
+ d_errors.each do |key, error|
129
+ d_keys = (keys.dup << key)
130
+
74
131
  error = error.first
75
- field_error_dom = options.delete :tmpl
76
- field_error_dom = DOM.new('<span class="field-error"><span>') unless field_error_dom
77
- field_error_dom.html _error_name(key, error)
78
132
 
79
- field = _dom.find("input[name='#{key}']")
80
- field.before field_error_dom.dom
133
+ if error.is_a? Hash
134
+ d_options = options.dup
135
+ d_options[:keys] = d_keys
136
+ d_options[:override_errors] = d_errors[key].first
137
+
138
+ display_errors d_options
139
+ else
140
+ name = d_keys.each_with_index.map do |field, i|
141
+ i != 0 ? "[#{field}]" : field
142
+ end.join
143
+
144
+ field_error_dom = options.delete :tmpl
145
+ field_error_dom = DOM.new('<span class="field-error"><span>') unless field_error_dom
146
+ field_error_dom.html _error_name(key, error)
147
+
148
+ field = _dom.find("input[name='#{name}']")
149
+ field.before field_error_dom.dom
150
+ end
151
+ end
152
+ end
153
+ alias_method :render_errors, :display_errors
154
+
155
+ def render_values dom = false, key = false, data = false
156
+ dom = _options[:dom] unless dom
157
+ key = _options[:key] if !key && _options.key?(:key)
158
+ data = attributes unless data
159
+
160
+ data.each do |k, v|
161
+ k = "#{key}[#{k}]" if !key.nil?
162
+ if v.is_a?(Hash)
163
+ render_values dom, k, v
164
+ else
165
+ dom.find('input, select') do |element|
166
+ if element['name'] == k
167
+ case element.name
168
+ when 'select'
169
+ element.find('option').each do |x|
170
+ x['selected'] = true if x['value']==v.to_s
171
+ end
172
+ when 'input'
173
+ element['value'] = v.to_s
174
+ end
175
+ end
176
+ end
177
+ end
81
178
  end
82
179
  end
83
180
 
84
181
  protected
85
182
 
183
+ def self._attr_accessors
184
+ @_attr_accessors
185
+ end
186
+
187
+ def _attributes
188
+ @_attributes ||= []
189
+ end
190
+
191
+ def _attr_accessors
192
+ self.class._attr_accessors
193
+ end
194
+
86
195
  def _options
87
196
  @_options
88
197
  end
@@ -103,6 +212,10 @@ class Roda
103
212
  error
104
213
  end
105
214
  end
215
+
216
+ def empty?
217
+ _attributes.empty?
218
+ end
106
219
  end
107
220
  end
108
221
  end