marty 0.5.12

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 (345) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +84 -0
  4. data/Rakefile +29 -0
  5. data/app/assets/javascripts/marty/application.js +15 -0
  6. data/app/assets/stylesheets/marty/application.css +13 -0
  7. data/app/components/marty/api_auth_view.rb +32 -0
  8. data/app/components/marty/auth_app.rb +55 -0
  9. data/app/components/marty/auth_app.rb~ +51 -0
  10. data/app/components/marty/auth_app/javascripts/auth_app.js +91 -0
  11. data/app/components/marty/auth_app/javascripts/auth_app.js~ +91 -0
  12. data/app/components/marty/cm_form_panel.rb~ +5 -0
  13. data/app/components/marty/cm_grid_panel.rb~ +35 -0
  14. data/app/components/marty/data_import_view.rb~ +142 -0
  15. data/app/components/marty/extras/layout.rb +46 -0
  16. data/app/components/marty/extras/layout.rb~ +46 -0
  17. data/app/components/marty/extras/misc.rb +18 -0
  18. data/app/components/marty/form.rb +6 -0
  19. data/app/components/marty/grid.rb +45 -0
  20. data/app/components/marty/grid_append_only.rb +12 -0
  21. data/app/components/marty/import_type_view.rb +53 -0
  22. data/app/components/marty/live_search_grid_panel.rb +46 -0
  23. data/app/components/marty/live_search_grid_panel.rb~ +49 -0
  24. data/app/components/marty/main_auth_app.rb +269 -0
  25. data/app/components/marty/main_auth_app.rb~ +238 -0
  26. data/app/components/marty/mcfly_grid_panel.rb +62 -0
  27. data/app/components/marty/mcfly_grid_panel.rb~ +80 -0
  28. data/app/components/marty/new_posting_form.rb +46 -0
  29. data/app/components/marty/new_posting_form.rb~ +46 -0
  30. data/app/components/marty/new_posting_window.rb +21 -0
  31. data/app/components/marty/new_posting_window.rb~ +21 -0
  32. data/app/components/marty/panel.rb +12 -0
  33. data/app/components/marty/pivot_grid.rb +52 -0
  34. data/app/components/marty/pivot_grid/endpoints.rb +45 -0
  35. data/app/components/marty/pivot_grid/javascripts/extensions.js +150 -0
  36. data/app/components/marty/pivot_grid/javascripts/pivot_grid.js +86 -0
  37. data/app/components/marty/pivot_grid/services.rb +44 -0
  38. data/app/components/marty/posting_grid.rb +139 -0
  39. data/app/components/marty/posting_grid.rb~ +140 -0
  40. data/app/components/marty/posting_window.rb +27 -0
  41. data/app/components/marty/promise_view.rb +177 -0
  42. data/app/components/marty/promise_view.rb~ +157 -0
  43. data/app/components/marty/promise_view/stylesheets/promise_view.css +26 -0
  44. data/app/components/marty/promise_view/stylesheets/promise_view.css~ +15 -0
  45. data/app/components/marty/report_form.rb +225 -0
  46. data/app/components/marty/report_form.rb~ +217 -0
  47. data/app/components/marty/report_select.rb +145 -0
  48. data/app/components/marty/report_select.rb~ +133 -0
  49. data/app/components/marty/reporting.rb +39 -0
  50. data/app/components/marty/reporting.rb~ +39 -0
  51. data/app/components/marty/script_detail.rb~ +430 -0
  52. data/app/components/marty/script_form.rb +233 -0
  53. data/app/components/marty/script_form.rb~ +233 -0
  54. data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js +698 -0
  55. data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js~ +909 -0
  56. data/app/components/marty/script_form/javascripts/codemirror.js +3130 -0
  57. data/app/components/marty/script_form/javascripts/mode/clike/clike.js +284 -0
  58. data/app/components/marty/script_form/javascripts/mode/clike/index.html +102 -0
  59. data/app/components/marty/script_form/javascripts/mode/clike/scala.html +766 -0
  60. data/app/components/marty/script_form/javascripts/mode/clojure/clojure.js +206 -0
  61. data/app/components/marty/script_form/javascripts/mode/clojure/index.html +67 -0
  62. data/app/components/marty/script_form/javascripts/mode/coffeescript/LICENSE +22 -0
  63. data/app/components/marty/script_form/javascripts/mode/coffeescript/coffeescript.js +346 -0
  64. data/app/components/marty/script_form/javascripts/mode/coffeescript/index.html +728 -0
  65. data/app/components/marty/script_form/javascripts/mode/commonlisp/commonlisp.js +101 -0
  66. data/app/components/marty/script_form/javascripts/mode/commonlisp/index.html +165 -0
  67. data/app/components/marty/script_form/javascripts/mode/css/css.js +448 -0
  68. data/app/components/marty/script_form/javascripts/mode/css/index.html +58 -0
  69. data/app/components/marty/script_form/javascripts/mode/css/test.js +501 -0
  70. data/app/components/marty/script_form/javascripts/mode/delorean/delorean.js +189 -0
  71. data/app/components/marty/script_form/javascripts/mode/diff/diff.js +32 -0
  72. data/app/components/marty/script_form/javascripts/mode/diff/index.html +105 -0
  73. data/app/components/marty/script_form/javascripts/mode/ecl/ecl.js +203 -0
  74. data/app/components/marty/script_form/javascripts/mode/ecl/index.html +42 -0
  75. data/app/components/marty/script_form/javascripts/mode/erlang/erlang.js +463 -0
  76. data/app/components/marty/script_form/javascripts/mode/erlang/index.html +63 -0
  77. data/app/components/marty/script_form/javascripts/mode/gfm/gfm.js +150 -0
  78. data/app/components/marty/script_form/javascripts/mode/gfm/index.html +48 -0
  79. data/app/components/marty/script_form/javascripts/mode/go/go.js +170 -0
  80. data/app/components/marty/script_form/javascripts/mode/go/index.html +73 -0
  81. data/app/components/marty/script_form/javascripts/mode/groovy/groovy.js +210 -0
  82. data/app/components/marty/script_form/javascripts/mode/groovy/index.html +72 -0
  83. data/app/components/marty/script_form/javascripts/mode/haskell/haskell.js +242 -0
  84. data/app/components/marty/script_form/javascripts/mode/haskell/index.html +61 -0
  85. data/app/components/marty/script_form/javascripts/mode/haxe/haxe.js +429 -0
  86. data/app/components/marty/script_form/javascripts/mode/haxe/index.html +91 -0
  87. data/app/components/marty/script_form/javascripts/mode/htmlembedded/htmlembedded.js +72 -0
  88. data/app/components/marty/script_form/javascripts/mode/htmlembedded/index.html +50 -0
  89. data/app/components/marty/script_form/javascripts/mode/htmlmixed/htmlmixed.js +84 -0
  90. data/app/components/marty/script_form/javascripts/mode/htmlmixed/index.html +52 -0
  91. data/app/components/marty/script_form/javascripts/mode/javascript/index.html +78 -0
  92. data/app/components/marty/script_form/javascripts/mode/javascript/javascript.js +361 -0
  93. data/app/components/marty/script_form/javascripts/mode/jinja2/index.html +38 -0
  94. data/app/components/marty/script_form/javascripts/mode/jinja2/jinja2.js +42 -0
  95. data/app/components/marty/script_form/javascripts/mode/less/index.html +740 -0
  96. data/app/components/marty/script_form/javascripts/mode/less/less.js +266 -0
  97. data/app/components/marty/script_form/javascripts/mode/lua/index.html +73 -0
  98. data/app/components/marty/script_form/javascripts/mode/lua/lua.js +140 -0
  99. data/app/components/marty/script_form/javascripts/mode/markdown/index.html +343 -0
  100. data/app/components/marty/script_form/javascripts/mode/markdown/markdown.js +382 -0
  101. data/app/components/marty/script_form/javascripts/mode/markdown/test.js +1084 -0
  102. data/app/components/marty/script_form/javascripts/mode/mysql/index.html +42 -0
  103. data/app/components/marty/script_form/javascripts/mode/mysql/mysql.js +186 -0
  104. data/app/components/marty/script_form/javascripts/mode/ntriples/index.html +33 -0
  105. data/app/components/marty/script_form/javascripts/mode/ntriples/ntriples.js +172 -0
  106. data/app/components/marty/script_form/javascripts/mode/ocaml/index.html +130 -0
  107. data/app/components/marty/script_form/javascripts/mode/ocaml/ocaml.js +114 -0
  108. data/app/components/marty/script_form/javascripts/mode/pascal/LICENSE +7 -0
  109. data/app/components/marty/script_form/javascripts/mode/pascal/index.html +49 -0
  110. data/app/components/marty/script_form/javascripts/mode/pascal/pascal.js +94 -0
  111. data/app/components/marty/script_form/javascripts/mode/perl/LICENSE +19 -0
  112. data/app/components/marty/script_form/javascripts/mode/perl/index.html +63 -0
  113. data/app/components/marty/script_form/javascripts/mode/perl/perl.js +816 -0
  114. data/app/components/marty/script_form/javascripts/mode/php/index.html +49 -0
  115. data/app/components/marty/script_form/javascripts/mode/php/php.js +148 -0
  116. data/app/components/marty/script_form/javascripts/mode/pig/index.html +43 -0
  117. data/app/components/marty/script_form/javascripts/mode/pig/pig.js +172 -0
  118. data/app/components/marty/script_form/javascripts/mode/plsql/index.html +63 -0
  119. data/app/components/marty/script_form/javascripts/mode/plsql/plsql.js +217 -0
  120. data/app/components/marty/script_form/javascripts/mode/properties/index.html +41 -0
  121. data/app/components/marty/script_form/javascripts/mode/properties/properties.js +63 -0
  122. data/app/components/marty/script_form/javascripts/mode/python/LICENSE.txt +21 -0
  123. data/app/components/marty/script_form/javascripts/mode/python/index.html +123 -0
  124. data/app/components/marty/script_form/javascripts/mode/python/python.js +338 -0
  125. data/app/components/marty/script_form/javascripts/mode/r/LICENSE +24 -0
  126. data/app/components/marty/script_form/javascripts/mode/r/index.html +74 -0
  127. data/app/components/marty/script_form/javascripts/mode/r/r.js +141 -0
  128. data/app/components/marty/script_form/javascripts/mode/rpm/changes/changes.js +19 -0
  129. data/app/components/marty/script_form/javascripts/mode/rpm/changes/index.html +54 -0
  130. data/app/components/marty/script_form/javascripts/mode/rpm/spec/index.html +100 -0
  131. data/app/components/marty/script_form/javascripts/mode/rpm/spec/spec.css +5 -0
  132. data/app/components/marty/script_form/javascripts/mode/rpm/spec/spec.js +66 -0
  133. data/app/components/marty/script_form/javascripts/mode/rst/index.html +526 -0
  134. data/app/components/marty/script_form/javascripts/mode/rst/rst.js +326 -0
  135. data/app/components/marty/script_form/javascripts/mode/ruby/LICENSE +24 -0
  136. data/app/components/marty/script_form/javascripts/mode/ruby/index.html +172 -0
  137. data/app/components/marty/script_form/javascripts/mode/ruby/ruby.js +195 -0
  138. data/app/components/marty/script_form/javascripts/mode/rust/index.html +49 -0
  139. data/app/components/marty/script_form/javascripts/mode/rust/rust.js +432 -0
  140. data/app/components/marty/script_form/javascripts/mode/scheme/index.html +65 -0
  141. data/app/components/marty/script_form/javascripts/mode/scheme/scheme.js +230 -0
  142. data/app/components/marty/script_form/javascripts/mode/shell/index.html +50 -0
  143. data/app/components/marty/script_form/javascripts/mode/shell/shell.js +118 -0
  144. data/app/components/marty/script_form/javascripts/mode/sieve/LICENSE +23 -0
  145. data/app/components/marty/script_form/javascripts/mode/sieve/index.html +81 -0
  146. data/app/components/marty/script_form/javascripts/mode/sieve/sieve.js +156 -0
  147. data/app/components/marty/script_form/javascripts/mode/smalltalk/index.html +56 -0
  148. data/app/components/marty/script_form/javascripts/mode/smalltalk/smalltalk.js +139 -0
  149. data/app/components/marty/script_form/javascripts/mode/smarty/index.html +83 -0
  150. data/app/components/marty/script_form/javascripts/mode/smarty/smarty.js +148 -0
  151. data/app/components/marty/script_form/javascripts/mode/sparql/index.html +41 -0
  152. data/app/components/marty/script_form/javascripts/mode/sparql/sparql.js +143 -0
  153. data/app/components/marty/script_form/javascripts/mode/stex/index.html +98 -0
  154. data/app/components/marty/script_form/javascripts/mode/stex/stex.js +182 -0
  155. data/app/components/marty/script_form/javascripts/mode/stex/test.js +343 -0
  156. data/app/components/marty/script_form/javascripts/mode/tiddlywiki/index.html +141 -0
  157. data/app/components/marty/script_form/javascripts/mode/tiddlywiki/tiddlywiki.css +14 -0
  158. data/app/components/marty/script_form/javascripts/mode/tiddlywiki/tiddlywiki.js +384 -0
  159. data/app/components/marty/script_form/javascripts/mode/tiki/index.html +83 -0
  160. data/app/components/marty/script_form/javascripts/mode/tiki/tiki.css +26 -0
  161. data/app/components/marty/script_form/javascripts/mode/tiki/tiki.js +309 -0
  162. data/app/components/marty/script_form/javascripts/mode/vb/LICENSE.txt +21 -0
  163. data/app/components/marty/script_form/javascripts/mode/vb/index.html +89 -0
  164. data/app/components/marty/script_form/javascripts/mode/vb/vb.js +260 -0
  165. data/app/components/marty/script_form/javascripts/mode/vbscript/index.html +43 -0
  166. data/app/components/marty/script_form/javascripts/mode/vbscript/vbscript.js +26 -0
  167. data/app/components/marty/script_form/javascripts/mode/velocity/index.html +104 -0
  168. data/app/components/marty/script_form/javascripts/mode/velocity/velocity.js +146 -0
  169. data/app/components/marty/script_form/javascripts/mode/verilog/index.html +211 -0
  170. data/app/components/marty/script_form/javascripts/mode/verilog/verilog.js +194 -0
  171. data/app/components/marty/script_form/javascripts/mode/xml/index.html +45 -0
  172. data/app/components/marty/script_form/javascripts/mode/xml/xml.js +318 -0
  173. data/app/components/marty/script_form/javascripts/mode/xquery/LICENSE +20 -0
  174. data/app/components/marty/script_form/javascripts/mode/xquery/index.html +223 -0
  175. data/app/components/marty/script_form/javascripts/mode/xquery/test/index.html +27 -0
  176. data/app/components/marty/script_form/javascripts/mode/xquery/test/testBase.js +42 -0
  177. data/app/components/marty/script_form/javascripts/mode/xquery/test/testEmptySequenceKeyword.js +16 -0
  178. data/app/components/marty/script_form/javascripts/mode/xquery/test/testMultiAttr.js +16 -0
  179. data/app/components/marty/script_form/javascripts/mode/xquery/test/testNamespaces.js +91 -0
  180. data/app/components/marty/script_form/javascripts/mode/xquery/test/testProcessingInstructions.js +16 -0
  181. data/app/components/marty/script_form/javascripts/mode/xquery/test/testQuotes.js +19 -0
  182. data/app/components/marty/script_form/javascripts/mode/xquery/xquery.js +451 -0
  183. data/app/components/marty/script_form/javascripts/mode/yaml/index.html +68 -0
  184. data/app/components/marty/script_form/javascripts/mode/yaml/yaml.js +95 -0
  185. data/app/components/marty/script_form/javascripts/util/closetag.js +164 -0
  186. data/app/components/marty/script_form/javascripts/util/dialog.css +27 -0
  187. data/app/components/marty/script_form/javascripts/util/dialog.js +70 -0
  188. data/app/components/marty/script_form/javascripts/util/foldcode.js +196 -0
  189. data/app/components/marty/script_form/javascripts/util/formatting.js +193 -0
  190. data/app/components/marty/script_form/javascripts/util/javascript-hint.js +134 -0
  191. data/app/components/marty/script_form/javascripts/util/loadmode.js +51 -0
  192. data/app/components/marty/script_form/javascripts/util/match-highlighter.js +44 -0
  193. data/app/components/marty/script_form/javascripts/util/multiplex.js +77 -0
  194. data/app/components/marty/script_form/javascripts/util/overlay.js +54 -0
  195. data/app/components/marty/script_form/javascripts/util/pig-hint.js +123 -0
  196. data/app/components/marty/script_form/javascripts/util/runmode-standalone.js +90 -0
  197. data/app/components/marty/script_form/javascripts/util/runmode.js +53 -0
  198. data/app/components/marty/script_form/javascripts/util/search.js +118 -0
  199. data/app/components/marty/script_form/javascripts/util/searchcursor.js +119 -0
  200. data/app/components/marty/script_form/javascripts/util/simple-hint.css +16 -0
  201. data/app/components/marty/script_form/javascripts/util/simple-hint.js +97 -0
  202. data/app/components/marty/script_form/javascripts/util/xml-hint.js +137 -0
  203. data/app/components/marty/script_form/stylesheets/codemirror.css +172 -0
  204. data/app/components/marty/script_form/stylesheets/delorean.css +10 -0
  205. data/app/components/marty/script_form/stylesheets/theme/ambiance.css +81 -0
  206. data/app/components/marty/script_form/stylesheets/theme/blackboard.css +25 -0
  207. data/app/components/marty/script_form/stylesheets/theme/cobalt.css +18 -0
  208. data/app/components/marty/script_form/stylesheets/theme/eclipse.css +25 -0
  209. data/app/components/marty/script_form/stylesheets/theme/elegant.css +10 -0
  210. data/app/components/marty/script_form/stylesheets/theme/erlang-dark.css +21 -0
  211. data/app/components/marty/script_form/stylesheets/theme/lesser-dark.css +44 -0
  212. data/app/components/marty/script_form/stylesheets/theme/monokai.css +28 -0
  213. data/app/components/marty/script_form/stylesheets/theme/neat.css +9 -0
  214. data/app/components/marty/script_form/stylesheets/theme/night.css +21 -0
  215. data/app/components/marty/script_form/stylesheets/theme/rubyblue.css +21 -0
  216. data/app/components/marty/script_form/stylesheets/theme/vibrant-ink.css +27 -0
  217. data/app/components/marty/script_form/stylesheets/theme/xq-dark.css +46 -0
  218. data/app/components/marty/script_grid.rb +104 -0
  219. data/app/components/marty/script_grid.rb~ +99 -0
  220. data/app/components/marty/script_tester.rb +114 -0
  221. data/app/components/marty/script_tester.rb~ +213 -0
  222. data/app/components/marty/scripting.rb +132 -0
  223. data/app/components/marty/scripting.rb~ +124 -0
  224. data/app/components/marty/select_report.rb~ +143 -0
  225. data/app/components/marty/simple_app.rb +97 -0
  226. data/app/components/marty/simple_app.rb~ +101 -0
  227. data/app/components/marty/simple_app/javascripts/simple_app.js +50 -0
  228. data/app/components/marty/simple_app/javascripts/statusbar_ext.js +8 -0
  229. data/app/components/marty/tag_grid.rb +83 -0
  230. data/app/components/marty/tag_grid.rb~ +89 -0
  231. data/app/components/marty/tree_panel.rb~ +256 -0
  232. data/app/components/marty/tree_panel/javascripts/tree_panel.js~ +317 -0
  233. data/app/components/marty/user_pivot.rb +128 -0
  234. data/app/components/marty/user_view.rb +181 -0
  235. data/app/components/marty/user_view.rb~ +188 -0
  236. data/app/controllers/marty/application_controller.rb +124 -0
  237. data/app/controllers/marty/application_controller.rb~ +133 -0
  238. data/app/controllers/marty/components_controller.rb +41 -0
  239. data/app/controllers/marty/components_controller.rb~ +37 -0
  240. data/app/controllers/marty/job_controller.rb +28 -0
  241. data/app/controllers/marty/job_controller.rb~ +28 -0
  242. data/app/controllers/marty/rpc_controller.rb +64 -0
  243. data/app/controllers/marty/rpc_controller.rb~ +61 -0
  244. data/app/helpers/marty/application_helper.rb +4 -0
  245. data/app/helpers/marty/script_set.rb +57 -0
  246. data/app/helpers/marty/script_set.rb~ +59 -0
  247. data/app/models/marty/api_auth.rb +44 -0
  248. data/app/models/marty/api_auth.rb~ +48 -0
  249. data/app/models/marty/base.rb +4 -0
  250. data/app/models/marty/data_change.rb +179 -0
  251. data/app/models/marty/data_change.rb~ +141 -0
  252. data/app/models/marty/enum.rb +22 -0
  253. data/app/models/marty/enum.rb~ +16 -0
  254. data/app/models/marty/import_type.rb +44 -0
  255. data/app/models/marty/import_type.rb~ +48 -0
  256. data/app/models/marty/poop.rb~ +169 -0
  257. data/app/models/marty/posting.rb +101 -0
  258. data/app/models/marty/posting.rb~ +86 -0
  259. data/app/models/marty/posting_type.rb +12 -0
  260. data/app/models/marty/posting_type.rb~ +21 -0
  261. data/app/models/marty/promise.rb +252 -0
  262. data/app/models/marty/promise.rb~ +196 -0
  263. data/app/models/marty/role.rb +6 -0
  264. data/app/models/marty/role.rb~ +10 -0
  265. data/app/models/marty/script.rb +144 -0
  266. data/app/models/marty/script.rb~ +62 -0
  267. data/app/models/marty/tag.rb +96 -0
  268. data/app/models/marty/tag.rb~ +91 -0
  269. data/app/models/marty/token.rb +30 -0
  270. data/app/models/marty/user.rb +146 -0
  271. data/app/models/marty/user.rb~ +148 -0
  272. data/app/models/marty/user_role.rb +7 -0
  273. data/app/models/marty/user_role.rb~ +13 -0
  274. data/app/views/layouts/marty/application.html.erb +12 -0
  275. data/app/views/layouts/marty/application.html.erb~ +11 -0
  276. data/config/locales/en.yml +134 -0
  277. data/config/routes.rb +6 -0
  278. data/config/routes.rb~ +10 -0
  279. data/db/migrate/001_create_marty_scripts.rb +14 -0
  280. data/db/migrate/003_create_marty_users.rb +12 -0
  281. data/db/migrate/004_create_marty_roles.rb +7 -0
  282. data/db/migrate/005_create_marty_user_roles.rb +14 -0
  283. data/db/migrate/006_create_marty_tokens.rb +14 -0
  284. data/db/migrate/008_create_marty_posting_types.rb +7 -0
  285. data/db/migrate/019_create_marty_postings.rb +18 -0
  286. data/db/migrate/019_create_marty_postings.rb~ +19 -0
  287. data/db/migrate/068_create_marty_import_types.rb +12 -0
  288. data/db/migrate/069_create_marty_import_synonyms.rb +15 -0
  289. data/db/migrate/070_create_versions.rb +18 -0
  290. data/db/migrate/071_add_object_changes_column_to_versions.rb +9 -0
  291. data/db/migrate/072_add_validation_function_to_import_types.rb +6 -0
  292. data/db/migrate/073_add_preprocess_function_to_import_types.rb +5 -0
  293. data/db/migrate/090_create_delayed_jobs.rb +22 -0
  294. data/db/migrate/091_create_marty_promises.rb +36 -0
  295. data/db/migrate/095_create_marty_tags.rb +14 -0
  296. data/db/migrate/095_create_marty_tags.rb~ +19 -0
  297. data/db/migrate/096_add_user_roles_to_import_types.rb +11 -0
  298. data/db/migrate/097_drop_versions.rb +9 -0
  299. data/db/migrate/098_create_marty_api_auths.rb +20 -0
  300. data/db/seeds.rb +48 -0
  301. data/lib/marty.rb +18 -0
  302. data/lib/marty.rb~ +13 -0
  303. data/lib/marty/content_handler.rb +97 -0
  304. data/lib/marty/content_handler.rb~ +93 -0
  305. data/lib/marty/data_conversion.rb +298 -0
  306. data/lib/marty/data_exporter.rb +150 -0
  307. data/lib/marty/data_exporter.rb~ +137 -0
  308. data/lib/marty/data_importer.rb +122 -0
  309. data/lib/marty/data_importer.rb~ +114 -0
  310. data/lib/marty/data_row_processor.rb~ +206 -0
  311. data/lib/marty/drop_folder_hook.rb~ +17 -0
  312. data/lib/marty/engine.rb +10 -0
  313. data/lib/marty/folder_hook.rb~ +9 -0
  314. data/lib/marty/lazy_column_loader.rb +57 -0
  315. data/lib/marty/lazy_column_loader.rb~ +47 -0
  316. data/lib/marty/mcfly_query.rb +189 -0
  317. data/lib/marty/mcfly_query.rb~ +188 -0
  318. data/lib/marty/migrations.rb +108 -0
  319. data/lib/marty/migrations.rb~ +65 -0
  320. data/lib/marty/monkey.rb +163 -0
  321. data/lib/marty/monkey.rb~ +160 -0
  322. data/lib/marty/permissions.rb +64 -0
  323. data/lib/marty/permissions.rb~ +69 -0
  324. data/lib/marty/promise.rb~ +41 -0
  325. data/lib/marty/promise_job.rb +123 -0
  326. data/lib/marty/promise_job.rb~ +121 -0
  327. data/lib/marty/promise_proxy.rb +94 -0
  328. data/lib/marty/promise_proxy.rb~ +69 -0
  329. data/lib/marty/railtie.rb +5 -0
  330. data/lib/marty/relation.rb +39 -0
  331. data/lib/marty/util.rb +110 -0
  332. data/lib/marty/util.rb~ +80 -0
  333. data/lib/marty/version.rb +3 -0
  334. data/lib/marty/version.rb~ +3 -0
  335. data/lib/marty/xl.rb +527 -0
  336. data/lib/marty/xl.rb~ +526 -0
  337. data/lib/pyxll/README.txt +19 -0
  338. data/lib/pyxll/README.txt~ +16 -0
  339. data/lib/pyxll/gemini.py +155 -0
  340. data/lib/pyxll/gemini.py~ +110 -0
  341. data/lib/pyxll/pyxll.cfg +12 -0
  342. data/lib/pyxll/pyxll.cfg~ +12 -0
  343. data/lib/pyxll/sample.xlsx +0 -0
  344. data/lib/tasks/marty_tasks.rake +37 -0
  345. metadata +517 -0
@@ -0,0 +1,19 @@
1
+ require 'marty/migrations'
2
+
3
+ class CreateMartyPostings < McflyAppendOnlyMigration
4
+ include Marty::Migrations
5
+
6
+ def change
7
+ create_table :marty_postings do |t|
8
+ t.string :name, null: false
9
+ t.references :posting_type, null: false
10
+ t.boolean :is_test, null: false
11
+ t.string :comment, null: false
12
+ end
13
+
14
+ add_mcfly_index :marty_postings,
15
+ :name, :posting_type_id, :is_test
16
+
17
+ add_fk :postings, :posting_types
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ class AddUserRolesToImportTypes < ActiveRecord::Migration
2
+ include Marty::Migrations
3
+
4
+ def change
5
+ change_table :marty_import_types do |t|
6
+ t.references :role
7
+ end
8
+
9
+ add_fk :import_types, :roles
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class DropVersions < ActiveRecord::Migration
2
+ def self.up
3
+ drop_table :versions
4
+ end
5
+
6
+ def self.down
7
+ announce("No-op on DropVersions.down")
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ require 'mcfly'
2
+
3
+ class CreateMartyApiAuths < McflyMigration
4
+ include Marty::Migrations
5
+
6
+ def change
7
+ create_table :marty_api_auths do |t|
8
+ t.string :app_name, null: false, limit: 255
9
+ t.string :api_key, null: false, limit: 255
10
+ t.string :script_name, null: false, limit: 255
11
+ end
12
+
13
+ add_mcfly_unique_index(Marty::ApiAuth)
14
+ add_index :marty_api_auths, [:app_name,
15
+ :script_name,
16
+ :obsoleted_dt],
17
+ unique: true,
18
+ name: 'unique_marty_api_auths_2'
19
+ end
20
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,48 @@
1
+ # create system account if not there
2
+ system_login = Rails.configuration.marty.system_account || 'marty'
3
+ unless Marty::User.find_by_login(system_login)
4
+ user = Marty::User.new
5
+ user.login = system_login
6
+ user.firstname = system_login
7
+ user.lastname = system_login
8
+ user.active = true
9
+ user.save!
10
+ end
11
+
12
+ # FIXME: hacky -- globally changes whodunnit
13
+ Mcfly.whodunnit = Marty::User.find_by_login(system_login)
14
+
15
+ # Create all Marty roles from configuration
16
+ (Rails.configuration.marty.roles || []).each do |role|
17
+ Marty::Role.create(name: role.to_s)
18
+ end
19
+
20
+ # Give system account all roles
21
+ Marty::Role.all.map { |role|
22
+ ur = Marty::UserRole.new
23
+ ur.user = Mcfly.whodunnit
24
+ ur.role = role
25
+ ur.save
26
+ }
27
+
28
+ # FIXME: this is a hack. It's needed due to the fact that 'NOW'
29
+ # posting requires a PostingType.
30
+ Marty::PostingType.create name: 'BASE'
31
+
32
+ # Create NOW posting
33
+ unless Marty::Posting.find_by_name('NOW')
34
+ sn = Marty::Posting.new
35
+ # FIXME: this is Gemini-specific
36
+ sn.posting_type_id = Marty::PostingType['BASE'].id
37
+ sn.comment = '---'
38
+ sn.created_dt = 'infinity'
39
+ sn.save!
40
+ end
41
+
42
+ # Create DEV tag
43
+ unless Marty::Tag.find_by_name('DEV')
44
+ tag = Marty::Tag.new
45
+ tag.comment = '---'
46
+ tag.created_dt = 'infinity'
47
+ tag.save!
48
+ end
data/lib/marty.rb ADDED
@@ -0,0 +1,18 @@
1
+ # Do not change order of require, since there are some dependencies
2
+ # Do not require 'marty/permissions' - it relies on Rails being loaded first
3
+ require 'marty/railtie'
4
+ require 'marty/engine'
5
+ require 'marty/monkey'
6
+ require 'marty/mcfly_query'
7
+ require 'marty/util'
8
+ require 'marty/migrations'
9
+ require 'marty/data_exporter'
10
+ require 'marty/xl.rb'
11
+ require 'marty/data_conversion'
12
+ require 'marty/data_importer'
13
+ require 'marty/relation'
14
+ require 'marty/promise_job'
15
+ require 'marty/promise_proxy'
16
+ require 'marty/content_handler'
17
+ require 'marty/lazy_column_loader'
18
+ require 'marty/version'
data/lib/marty.rb~ ADDED
@@ -0,0 +1,13 @@
1
+ require 'marty/engine'
2
+ require 'marty/monkey'
3
+ require 'marty/mcfly_query'
4
+ require 'marty/util'
5
+ require 'marty/migrations'
6
+ require 'marty/data_exporter'
7
+ require 'marty/xl.rb'
8
+ require 'marty/data_importer'
9
+ require 'marty/promise_job'
10
+ require 'marty/promise_proxy'
11
+ require 'marty/content_handler'
12
+ require 'marty/lazy_column_loader'
13
+ require 'marty/version'
@@ -0,0 +1,97 @@
1
+ require 'csv'
2
+
3
+ module Marty::ContentHandler
4
+ GEN_FORMATS = {
5
+ "csv" => ['text/csv', 'download'],
6
+ "zip" => ['application/zip', 'download'],
7
+ "xlsx" => ['application/vnd.ms-excel', 'download'],
8
+ "html" => ['text/html', 'inline'],
9
+ "txt" => ['text/plain', 'inline'],
10
+ "json" => ['application/json', 'download'],
11
+
12
+ # hacky: default format is JSON
13
+ nil => ['application/json', 'download'],
14
+ }
15
+
16
+ def self.log_and_raise(err)
17
+ Marty::Util.logger.error err
18
+ raise err
19
+ end
20
+
21
+ def self.export(data, format, name)
22
+ begin
23
+ case format
24
+ when "csv"
25
+ # Somewhat hacky, if data is string => pass through as CSV.
26
+ # Should generalize to other data types, not just CSV.
27
+ res = data.is_a?(String) ? data : Marty::DataExporter.to_csv(data)
28
+ when "xlsx"
29
+ res = Marty::Xl.spreadsheet(data).to_stream.read
30
+ when "zip"
31
+ res = to_zip(data)
32
+ when nil, "json"
33
+ res, format = data.to_json, "json"
34
+ else
35
+ res, format = {error: "Unknown format: #{format}"}.to_json, "json"
36
+ end
37
+ rescue => exc
38
+ res, format =
39
+ {error: "Failed conversion #{format}: #{exc}"}.to_json, "json"
40
+ end
41
+
42
+ type, disposition = GEN_FORMATS[format]
43
+
44
+ return [res, type, disposition, "#{name}.#{format}"]
45
+ end
46
+
47
+ private
48
+
49
+ def self.sanitize_filename(filename)
50
+ filename.strip.
51
+ gsub(/[\\\/]/, '_').
52
+ gsub(/[^[:print:]]/, '_')
53
+ end
54
+
55
+ def self.uniq_filename(filename, fset)
56
+ (0..1000).each { |i|
57
+ post = i==0 ? "" : " (#{i})"
58
+ fn = filename + post
59
+ return fn unless fset.member? fn
60
+ }
61
+ filename
62
+ end
63
+
64
+ def self.to_zip_stream(stream, path, data)
65
+ fset = Set.new
66
+
67
+ data.each { |r|
68
+ title, format, result = r["title"], r["format"], r["result"]
69
+
70
+ log_and_raise "Result has no title" unless title
71
+ log_and_raise "Result has no result" unless result
72
+
73
+ if format == "zip"
74
+ to_zip_stream(stream, path + [title], result)
75
+ next
76
+ end
77
+
78
+ res_data, _type, _disposition, res_name = export(result, format, title)
79
+
80
+ filename = uniq_filename(sanitize_filename(res_name), fset)
81
+ fset.add filename
82
+
83
+ stream.put_next_entry((path + [filename]).join('/'))
84
+ stream.write res_data
85
+ }
86
+ end
87
+
88
+ def self.to_zip(data)
89
+ raise "Can't convert non-array data to zip format: #{data.class}" unless
90
+ data.is_a?(Array)
91
+
92
+ res = Zip::OutputStream.write_buffer do |stream|
93
+ to_zip_stream(stream, [], data)
94
+ end
95
+ res.string
96
+ end
97
+ end
@@ -0,0 +1,93 @@
1
+ module Marty::ContentHandler
2
+ GEN_FORMATS = {
3
+ "csv" => ['text/csv', 'download'],
4
+ "zip" => ['application/zip', 'download'],
5
+ "xlsx" => ['application/vnd.ms-excel', 'download'],
6
+ "html" => ['text/html', 'inline'],
7
+ "txt" => ['text/plain', 'inline'],
8
+ "json" => ['application/json', 'download'],
9
+
10
+ # hacky: default format is JSON
11
+ nil => ['application/json', 'download'],
12
+ }
13
+
14
+ def self.log_and_raise(err)
15
+ Marty::Util.logger.error err
16
+ raise err
17
+ end
18
+
19
+ def self.export(data, format, name)
20
+ begin
21
+ case format
22
+ when "csv"
23
+ res = Marty::DataExporter.to_csv(data)
24
+ when "xlsx"
25
+ res = Marty::Xl.spreadsheet(data).to_stream.read
26
+ when "zip"
27
+ res = to_zip(data)
28
+ when nil, "json"
29
+ res, format = data.to_json, "json"
30
+ else
31
+ res, format = {error: "Unknown format: #{format}"}.to_json, "json"
32
+ end
33
+ rescue => exc
34
+ res, format =
35
+ {error: "Failed conversion #{format}: #{exc}"}.to_json, "json"
36
+ end
37
+
38
+ type, disposition = GEN_FORMATS[format]
39
+
40
+ return [res, type, disposition, "#{name}.#{format}"]
41
+ end
42
+
43
+ private
44
+
45
+ def self.sanitize_filename(filename)
46
+ filename.strip.
47
+ gsub(/[\\\/]/, '_').
48
+ gsub(/[^[:print:]]/, '_')
49
+ end
50
+
51
+ def self.uniq_filename(filename, fset)
52
+ (0..1000).each { |i|
53
+ post = i==0 ? "" : " (#{i})"
54
+ fn = filename + post
55
+ return fn unless fset.member? fn
56
+ }
57
+ filename
58
+ end
59
+
60
+ def self.to_zip_stream(stream, path, data)
61
+ fset = Set.new
62
+
63
+ data.each { |r|
64
+ title, format, result = r["title"], r["format"], r["result"]
65
+
66
+ log_and_raise "Result has no title" unless title
67
+ log_and_raise "Result has no result" unless result
68
+
69
+ if format == "zip"
70
+ to_zip_stream(stream, path + [title], result)
71
+ next
72
+ end
73
+
74
+ res_data, _type, _disposition, res_name = export(result, format, title)
75
+
76
+ filename = uniq_filename(sanitize_filename(res_name), fset)
77
+ fset.add filename
78
+
79
+ stream.put_next_entry((path + [filename]).join('/'))
80
+ stream.write res_data
81
+ }
82
+ end
83
+
84
+ def self.to_zip(data)
85
+ raise "Can't convert non-array data to zip format: #{data.class}" unless
86
+ data.is_a?(Array)
87
+
88
+ res = Zip::OutputStream.write_buffer do |stream|
89
+ to_zip_stream(stream, [], data)
90
+ end
91
+ res.string
92
+ end
93
+ end
@@ -0,0 +1,298 @@
1
+ require 'mcfly'
2
+
3
+ class Marty::DataConversion
4
+ EXCEL_START_DATE = Date.parse('1/1/1900')-2
5
+
6
+ FLOAT_PAT = /^-?\d+(\.\d+)?$/
7
+
8
+ PATS = {
9
+ integer: /^-?\d+(\.0+)?$/,
10
+ float: FLOAT_PAT,
11
+ decimal: FLOAT_PAT,
12
+ }
13
+
14
+ # database types that can be converted to on import
15
+ DATABASE_TYPES = Set[
16
+ :boolean,
17
+ :string,
18
+ :text,
19
+ :integer,
20
+ :float,
21
+ :decimal,
22
+ :date,
23
+ :datetime,
24
+ :numrange,
25
+ :int4range,
26
+ :int8range,
27
+ :float_array,
28
+ :json,
29
+ :jsonb,
30
+ ]
31
+
32
+ def self.convert(v, type)
33
+ # Converts external data v (e.g. from a CSV, cut/paste) to
34
+ # ActiveRecord database data type.
35
+
36
+ pat = PATS[type]
37
+
38
+ raise "bad #{type} #{v.inspect}" if
39
+ v.is_a?(String) && pat && !(v =~ pat)
40
+
41
+ case type
42
+ when :boolean
43
+ case v.to_s.downcase
44
+ when "true", "1", "y" then true
45
+ when "false", "0", "n" then false
46
+ else raise "unknown boolean #{v}"
47
+ end
48
+ when :string, :text
49
+ v
50
+ when :integer
51
+ v.to_i
52
+ when :float
53
+ v.to_f
54
+ when :decimal
55
+ v.to_d
56
+ when :date
57
+ # Dates are kept as float in Google spreadsheets. Need to
58
+ # convert them to dates. FIXME: 'infinity' as a date in
59
+ # Rails 3.2 appears to be broken. Setting a date field to
60
+ # 'infinity' sets it to nil.
61
+ v =~ FLOAT_PAT ? EXCEL_START_DATE + v.to_f :
62
+ Mcfly.is_infinity(v) ? 'infinity' : v.to_date
63
+ when :datetime
64
+ Mcfly.is_infinity(v) ? 'infinity' : v.to_datetime
65
+ when :numrange, :int4range, :int8range
66
+ v.to_s
67
+ when :float_array, :json, :jsonb
68
+ JSON.parse Marty::DataExporter.decode_json(v)
69
+ else
70
+ raise "unknown type #{type} for #{v}"
71
+ end
72
+ end
73
+
74
+ ######################################################################
75
+
76
+ def self.assoc_keys(klass)
77
+ return Mcfly.mcfly_uniqueness(klass) if Mcfly.has_mcfly?(klass)
78
+ # FIXME: very hacky -- picks 1st non-id attr as the association
79
+ # key for regular (non-mcfly) AR models which don't have
80
+ # MARTY_IMPORT_UNIQUENESS.
81
+ klass.const_get(:MARTY_IMPORT_UNIQUENESS) rescue [
82
+ klass.attribute_names.reject{|x| x=="id"}.first.to_sym]
83
+ end
84
+
85
+ @@associations = {}
86
+
87
+ def self.associations(klass)
88
+ # build a profile for ActiveRecord klass associations which
89
+ # enables find/import of its database records
90
+
91
+ @@associations[klass] ||= klass.reflect_on_all_associations.
92
+ each_with_object({}) do
93
+ |assoc, h|
94
+
95
+ h[assoc.name.to_s] = {
96
+ assoc_keys: assoc_keys(assoc.klass),
97
+ assoc_class: assoc.klass,
98
+ foreign_key: assoc.foreign_key,
99
+ }
100
+ end
101
+ end
102
+
103
+ def self.assoc_cols(klass)
104
+ # array of klass association columns (e.g. ["xxx_id", ...])
105
+ associations(klass).values.map { |a| a[:foreign_key] }
106
+ end
107
+
108
+ ######################################################################
109
+
110
+ @@col_types = {}
111
+
112
+ def self.col_types(klass)
113
+ # build profile for ActiveRecord non-assoc columns -- used to
114
+ # find/import of klass database records.
115
+
116
+ @@col_types[klass] ||= klass.columns.each_with_object({}) do
117
+ |col, h|
118
+
119
+ assoc ||= associations(klass)
120
+ acols ||= assoc_cols(klass)
121
+
122
+ cn = col.name
123
+
124
+ # ignore mcfly cols
125
+ next if Mcfly::COLUMNS.member?(cn)
126
+
127
+ if acols.member?(cn)
128
+ h[cn] = assoc.values.detect { |a| a[:foreign_key] == cn }
129
+ else
130
+ # for JSON fields in Rails 3.x type is nil, so use sql_type
131
+ type = col.type || col.sql_type
132
+ type = "#{type}_array" if col.array
133
+ h[cn] = type.to_sym
134
+ end
135
+ end
136
+ end
137
+
138
+ def self.columns(klass)
139
+ # list of non-mcfly columns
140
+ col_types(klass).keys
141
+ end
142
+
143
+ ######################################################################
144
+
145
+ def self.find_row(klass, options, dt)
146
+ key_attrs = assoc_keys(klass)
147
+
148
+ raise "no key_attrs for #{klass}" unless key_attrs
149
+
150
+ find_options = options.select { |k,v| key_attrs.member? k.to_sym }
151
+
152
+ raise "no keys for #{klass} -- #{options}" if find_options.empty?
153
+
154
+ # unscope klass since we're sometimes sent lazy column classes
155
+ q = klass.unscoped.where(find_options)
156
+ q = q.where('obsoleted_dt >= ?', dt) if dt && Mcfly.has_mcfly?(klass)
157
+
158
+ # q.count is almost always 0 or 1 => hopefully it's not too slow on PG.
159
+ raise "too many results for: #{klass} -- #{options}" if q.count > 1
160
+
161
+ q.first
162
+ end
163
+
164
+ ######################################################################
165
+
166
+ def self.convert_row(klass, row, dt)
167
+ # Given row information from imports (usually csv row or hash),
168
+ # return a hash with fields converted into proper ruby types.
169
+
170
+ ctypes = col_types(klass)
171
+ assoc = associations(klass)
172
+
173
+ raise "bad row (extra columns?) -- #{row}" if row.has_key?(nil)
174
+
175
+ key_groups = row.keys.group_by {|x| x.to_s.split('__').first}
176
+
177
+ # FIXME: map all empty string values to nil --- this means that
178
+ # user can't import empty strings -- Perhaps, mapping "" -> nil
179
+ # should be optional?
180
+ row = row.each_with_object({}) {
181
+ |(k,v), h|
182
+ h[k.to_s] = v == '' ? nil : v
183
+ }
184
+
185
+ key_groups.each_with_object({}) do
186
+ |(ga, g), h|
187
+
188
+ # find the association's details
189
+ ai = assoc[ga]
190
+
191
+ unless ai
192
+ raise "unexpected grouping for non assoc #{g}" unless g.length == 1
193
+
194
+ type = ctypes[ga]
195
+
196
+ raise "unknown column #{ga} in #{klass}" unless type
197
+
198
+ v = row[ga]
199
+
200
+ if v.nil?
201
+ h[ga] = nil
202
+ elsif Hash === type
203
+ # got an id for an association -- FIXME: perhaps this should
204
+ # not be allowed at all?
205
+ raise "#{type[:assoc_class].name} with id #{v} not found" unless
206
+ type[:assoc_class].find_by_id(v)
207
+
208
+ h[ga] = v
209
+ else
210
+ # not an association, so we need to convert
211
+ h[ga] = convert(v, type)
212
+ end
213
+ next
214
+ end
215
+
216
+ srch_class = ai[:assoc_class]
217
+ fk = "#{ga}_id"
218
+
219
+ if g.length == 1
220
+ # optimization for case where we have a 1-key association
221
+ v = row[g.first]
222
+
223
+ # If group has only one attr and the attr is nil or AR obj, then
224
+ # we don't need to search.
225
+ if v.nil? || v.is_a?(ActiveRecord::Base)
226
+ h[fk] = v && v.id
227
+ next
228
+ end
229
+
230
+ # If it's an Enum, use the faster cached looked mechanism
231
+ if Marty::Enum === srch_class
232
+ h[fk] = srch_class[ v ].id
233
+ next
234
+ end
235
+ end
236
+
237
+ # group size > 1 or not an Enum, so it must be an association
238
+ raise "expected an association for #{ga}" unless ai
239
+
240
+ # build a new row map for this association, we need to convert
241
+ # it and search for it.
242
+ arow = g.each_with_object({}) do
243
+ |k, h|
244
+
245
+ # Some old exports don't provide full assoc__attr column names
246
+ # (e.g. 'xxx_name'). Instead the columns are just named by
247
+ # assoc (e.g. 'xxx').
248
+ gname, ka = k.split('__', 2)
249
+
250
+ ka ||= ai[:assoc_keys][0].to_s
251
+ h[ka] = row[k]
252
+ end
253
+
254
+ c_arow = convert_row(srch_class, arow, dt)
255
+ o_arow = find_row(srch_class, c_arow, dt)
256
+
257
+ raise "obj not found: #{ai[:assoc_class]}, #{c_arow}, #{dt}" unless o_arow
258
+
259
+ h[fk] = o_arow.id
260
+ end
261
+
262
+ end
263
+
264
+ ######################################################################
265
+
266
+ def self.create_or_update(klass, row, dt)
267
+ # Given a row data (usually from import) try to find the
268
+ # associated DB row from the klass keys. If found the row is
269
+ # updated using the dt datetime. Otherwise, a new row is created
270
+ # with the provided row data.
271
+
272
+ c_row = convert_row(klass, row.to_hash, dt)
273
+ obj = find_row(klass, c_row, dt)
274
+
275
+ obj ||= klass.new
276
+
277
+ c_row.each do
278
+ |k, v|
279
+ # For each attr, check to see if it's begin changed before
280
+ # setting it. The AR obj.changed? doesn't work properly
281
+ # with array, JSON or lazy attrs.
282
+ obj.send("#{k}=", v) if obj.send(k) != v
283
+ end
284
+
285
+ # FIXME: obj.changed? doesn't work properly for timestamp
286
+ # fields in Rails 3.2. It evaluates to true even when datetime
287
+ # is not changed. Caused by lack of awareness of timezones.
288
+ tag = obj.new_record? ? :create : (obj.changed? ? :update : :same)
289
+
290
+ raise "old created_dt >= current #{obj} #{obj.created_dt} #{dt}" if
291
+ (tag == :update) && dt && !Mcfly.is_infinity(dt) && (obj.created_dt > dt)
292
+
293
+ obj.created_dt = dt unless tag == :same || Mcfly.is_infinity(dt) || !dt
294
+ obj.save!
295
+
296
+ [tag, obj.id]
297
+ end
298
+ end