dbagile 0.0.1

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 (305) hide show
  1. data/LICENCE.textile +12 -0
  2. data/README.textile +89 -0
  3. data/bin/dba +22 -0
  4. data/lib/dbagile/adapter/sequel/class_methods.rb +18 -0
  5. data/lib/dbagile/adapter/sequel/connection.rb +38 -0
  6. data/lib/dbagile/adapter/sequel/data/table_driven.rb +30 -0
  7. data/lib/dbagile/adapter/sequel/data/transaction_driven.rb +43 -0
  8. data/lib/dbagile/adapter/sequel/schema/concrete_script.rb +135 -0
  9. data/lib/dbagile/adapter/sequel/schema/physical_dump.rb +106 -0
  10. data/lib/dbagile/adapter/sequel/schema/schema2sequel_args.rb +71 -0
  11. data/lib/dbagile/adapter/sequel/schema/table_driven.rb +52 -0
  12. data/lib/dbagile/adapter/sequel/schema/transaction_driven.rb +46 -0
  13. data/lib/dbagile/adapter/sequel/sequel_tracer.rb +144 -0
  14. data/lib/dbagile/adapter/sequel.rb +46 -0
  15. data/lib/dbagile/adapter.rb +15 -0
  16. data/lib/dbagile/command/api.rb +49 -0
  17. data/lib/dbagile/command/bulk/commons.rb +130 -0
  18. data/lib/dbagile/command/bulk/export.rb +99 -0
  19. data/lib/dbagile/command/bulk/import.rb +147 -0
  20. data/lib/dbagile/command/bulk.rb +3 -0
  21. data/lib/dbagile/command/class_methods.rb +103 -0
  22. data/lib/dbagile/command/db/add.rb +94 -0
  23. data/lib/dbagile/command/db/list.rb +40 -0
  24. data/lib/dbagile/command/db/ping.rb +49 -0
  25. data/lib/dbagile/command/db/rm.rb +52 -0
  26. data/lib/dbagile/command/db/stage.rb +81 -0
  27. data/lib/dbagile/command/db/use.rb +48 -0
  28. data/lib/dbagile/command/db.rb +6 -0
  29. data/lib/dbagile/command/dba.rb +121 -0
  30. data/lib/dbagile/command/help.rb +50 -0
  31. data/lib/dbagile/command/repo/create.rb +54 -0
  32. data/lib/dbagile/command/repo.rb +1 -0
  33. data/lib/dbagile/command/robust.rb +86 -0
  34. data/lib/dbagile/command/schema/check.rb +59 -0
  35. data/lib/dbagile/command/schema/commons.rb +118 -0
  36. data/lib/dbagile/command/schema/diff.rb +101 -0
  37. data/lib/dbagile/command/schema/dump.rb +48 -0
  38. data/lib/dbagile/command/schema/merge.rb +55 -0
  39. data/lib/dbagile/command/schema/sql_script.rb +124 -0
  40. data/lib/dbagile/command/schema.rb +6 -0
  41. data/lib/dbagile/command/sql/drop.rb +40 -0
  42. data/lib/dbagile/command/sql/heading.rb +34 -0
  43. data/lib/dbagile/command/sql/send.rb +67 -0
  44. data/lib/dbagile/command/sql/show.rb +42 -0
  45. data/lib/dbagile/command/sql.rb +4 -0
  46. data/lib/dbagile/command/web/tools.rb +23 -0
  47. data/lib/dbagile/command/web.rb +1 -0
  48. data/lib/dbagile/command.rb +158 -0
  49. data/lib/dbagile/contract/connection.rb +66 -0
  50. data/lib/dbagile/contract/data/dataset.rb +69 -0
  51. data/lib/dbagile/contract/data/table_driven.rb +49 -0
  52. data/lib/dbagile/contract/data/transaction_driven.rb +74 -0
  53. data/lib/dbagile/contract/data.rb +3 -0
  54. data/lib/dbagile/contract/robust/helpers.rb +19 -0
  55. data/lib/dbagile/contract/robust/optimistic/data/table_driven.rb +31 -0
  56. data/lib/dbagile/contract/robust/optimistic/data/transaction_driven.rb +45 -0
  57. data/lib/dbagile/contract/robust/optimistic/schema/table_driven.rb +53 -0
  58. data/lib/dbagile/contract/robust/optimistic/schema/transaction_driven.rb +45 -0
  59. data/lib/dbagile/contract/robust/optimistic.rb +18 -0
  60. data/lib/dbagile/contract/robust.rb +20 -0
  61. data/lib/dbagile/contract/schema/table_driven.rb +89 -0
  62. data/lib/dbagile/contract/schema/transaction_driven.rb +68 -0
  63. data/lib/dbagile/contract/schema.rb +2 -0
  64. data/lib/dbagile/contract/utils/delegate.rb +17 -0
  65. data/lib/dbagile/contract/utils/full.rb +13 -0
  66. data/lib/dbagile/contract/utils.rb +2 -0
  67. data/lib/dbagile/contract.rb +5 -0
  68. data/lib/dbagile/core/chain.rb +92 -0
  69. data/lib/dbagile/core/connection.rb +51 -0
  70. data/lib/dbagile/core/database.rb +221 -0
  71. data/lib/dbagile/core/io/dsl.rb +95 -0
  72. data/lib/dbagile/core/io/robustness.rb +82 -0
  73. data/lib/dbagile/core/io.rb +2 -0
  74. data/lib/dbagile/core/repository/builder.rb +67 -0
  75. data/lib/dbagile/core/repository/yaml_methods.rb +82 -0
  76. data/lib/dbagile/core/repository.rb +211 -0
  77. data/lib/dbagile/core/schema/builder/coercion.rb +210 -0
  78. data/lib/dbagile/core/schema/builder/concept_factory.rb +61 -0
  79. data/lib/dbagile/core/schema/builder.rb +187 -0
  80. data/lib/dbagile/core/schema/composite.rb +239 -0
  81. data/lib/dbagile/core/schema/computations/filter.rb +40 -0
  82. data/lib/dbagile/core/schema/computations/merge.rb +55 -0
  83. data/lib/dbagile/core/schema/computations/minus.rb +44 -0
  84. data/lib/dbagile/core/schema/computations/split.rb +37 -0
  85. data/lib/dbagile/core/schema/computations.rb +4 -0
  86. data/lib/dbagile/core/schema/database_schema.rb +129 -0
  87. data/lib/dbagile/core/schema/errors.rb +173 -0
  88. data/lib/dbagile/core/schema/logical/attribute.rb +68 -0
  89. data/lib/dbagile/core/schema/logical/constraint/candidate_key.rb +70 -0
  90. data/lib/dbagile/core/schema/logical/constraint/foreign_key.rb +121 -0
  91. data/lib/dbagile/core/schema/logical/constraint.rb +58 -0
  92. data/lib/dbagile/core/schema/logical/constraints.rb +28 -0
  93. data/lib/dbagile/core/schema/logical/heading.rb +47 -0
  94. data/lib/dbagile/core/schema/logical/relvar.rb +81 -0
  95. data/lib/dbagile/core/schema/logical.rb +24 -0
  96. data/lib/dbagile/core/schema/migrate/abstract_script.rb +35 -0
  97. data/lib/dbagile/core/schema/migrate/collapse_table.rb +15 -0
  98. data/lib/dbagile/core/schema/migrate/create_table.rb +15 -0
  99. data/lib/dbagile/core/schema/migrate/drop_table.rb +15 -0
  100. data/lib/dbagile/core/schema/migrate/expand_table.rb +15 -0
  101. data/lib/dbagile/core/schema/migrate/operation.rb +141 -0
  102. data/lib/dbagile/core/schema/migrate/stager.rb +282 -0
  103. data/lib/dbagile/core/schema/migrate.rb +2 -0
  104. data/lib/dbagile/core/schema/part.rb +114 -0
  105. data/lib/dbagile/core/schema/physical/index.rb +64 -0
  106. data/lib/dbagile/core/schema/physical/indexes.rb +12 -0
  107. data/lib/dbagile/core/schema/physical.rb +26 -0
  108. data/lib/dbagile/core/schema/robustness.rb +39 -0
  109. data/lib/dbagile/core/schema/schema_object.rb +94 -0
  110. data/lib/dbagile/core/schema.rb +254 -0
  111. data/lib/dbagile/core/transaction.rb +74 -0
  112. data/lib/dbagile/core.rb +7 -0
  113. data/lib/dbagile/environment/buffering.rb +45 -0
  114. data/lib/dbagile/environment/delegator.rb +59 -0
  115. data/lib/dbagile/environment/interactions.rb +208 -0
  116. data/lib/dbagile/environment/on_error.rb +47 -0
  117. data/lib/dbagile/environment/repository.rb +161 -0
  118. data/lib/dbagile/environment/robustness.rb +7 -0
  119. data/lib/dbagile/environment/testing.rb +23 -0
  120. data/lib/dbagile/environment.rb +122 -0
  121. data/lib/dbagile/errors.rb +30 -0
  122. data/lib/dbagile/io/csv.rb +99 -0
  123. data/lib/dbagile/io/json.rb +41 -0
  124. data/lib/dbagile/io/pretty_table.rb +128 -0
  125. data/lib/dbagile/io/ruby.rb +62 -0
  126. data/lib/dbagile/io/text.rb +18 -0
  127. data/lib/dbagile/io/type_safe.rb +65 -0
  128. data/lib/dbagile/io/xml.rb +35 -0
  129. data/lib/dbagile/io/yaml.rb +30 -0
  130. data/lib/dbagile/io.rb +94 -0
  131. data/lib/dbagile/loader.rb +16 -0
  132. data/lib/dbagile/plugin.rb +29 -0
  133. data/lib/dbagile/restful/client/delete.rb +22 -0
  134. data/lib/dbagile/restful/client/get.rb +24 -0
  135. data/lib/dbagile/restful/client/post.rb +22 -0
  136. data/lib/dbagile/restful/client/utils.rb +16 -0
  137. data/lib/dbagile/restful/client.rb +41 -0
  138. data/lib/dbagile/restful/middleware/delete.rb +22 -0
  139. data/lib/dbagile/restful/middleware/get.rb +27 -0
  140. data/lib/dbagile/restful/middleware/one_database.rb +82 -0
  141. data/lib/dbagile/restful/middleware/post.rb +23 -0
  142. data/lib/dbagile/restful/middleware/utils.rb +65 -0
  143. data/lib/dbagile/restful/middleware.rb +54 -0
  144. data/lib/dbagile/restful/server.rb +65 -0
  145. data/lib/dbagile/restful.rb +9 -0
  146. data/lib/dbagile/robustness/dependencies.rb +36 -0
  147. data/lib/dbagile/robustness/file_system.rb +53 -0
  148. data/lib/dbagile/robustness.rb +14 -0
  149. data/lib/dbagile/tools/file_system.rb +24 -0
  150. data/lib/dbagile/tools/math.rb +11 -0
  151. data/lib/dbagile/tools/ordered_hash.rb +39 -0
  152. data/lib/dbagile/tools/ruby.rb +78 -0
  153. data/lib/dbagile/tools/string.rb +6 -0
  154. data/lib/dbagile/tools/tuple.rb +49 -0
  155. data/lib/dbagile/tools.rb +6 -0
  156. data/lib/dbagile.rb +66 -0
  157. data/test/assumptions/equality.spec +11 -0
  158. data/test/assumptions/fixtures.rb +39 -0
  159. data/test/assumptions/inheritance.spec +17 -0
  160. data/test/assumptions/sequel/autonumber.spec +19 -0
  161. data/test/assumptions/sequel/connect.spec +29 -0
  162. data/test/assumptions/sequel/test.db +0 -0
  163. data/test/assumptions/stdlib/pathname.spec +13 -0
  164. data/test/assumptions/yaml/fixtures.rb +25 -0
  165. data/test/assumptions/yaml/to_yaml.spec +10 -0
  166. data/test/assumptions.spec +2 -0
  167. data/test/commands/bulk/export.spec +100 -0
  168. data/test/commands/bulk/import.spec +49 -0
  169. data/test/commands/db/add.spec +31 -0
  170. data/test/commands/db/list.spec +29 -0
  171. data/test/commands/db/ping.spec +21 -0
  172. data/test/commands/db/rm.spec +18 -0
  173. data/test/commands/db/use.spec +18 -0
  174. data/test/commands/dba.spec +54 -0
  175. data/test/commands/repo/create.spec +30 -0
  176. data/test/commands/schema/check.spec +25 -0
  177. data/test/commands/schema/diff.spec +30 -0
  178. data/test/commands/schema/dump.spec +23 -0
  179. data/test/commands/schema/fixtures/add_constraint.yaml +30 -0
  180. data/test/commands/schema/fixtures/announced.yaml +28 -0
  181. data/test/commands/schema/fixtures/effective.yaml +20 -0
  182. data/test/commands/schema/fixtures/invalid.yaml +6 -0
  183. data/test/commands/schema/sql_script.spec +56 -0
  184. data/test/commands/sql/drop.spec +25 -0
  185. data/test/commands/sql/heading.spec +7 -0
  186. data/test/commands/sql/scripts/delete.sql +1 -0
  187. data/test/commands/sql/scripts/insert.sql +2 -0
  188. data/test/commands/sql/send.spec +29 -0
  189. data/test/commands/sql/show.spec +17 -0
  190. data/test/commands.spec +138 -0
  191. data/test/contract/connection/transaction.ex +11 -0
  192. data/test/contract/connection.spec +9 -0
  193. data/test/contract/data/dataset/columns.ex +5 -0
  194. data/test/contract/data/dataset/count.ex +5 -0
  195. data/test/contract/data/dataset.spec +9 -0
  196. data/test/contract/data/table_driven/dataset.ex +31 -0
  197. data/test/contract/data/table_driven/exists_q.ex +27 -0
  198. data/test/contract/data/table_driven.spec +9 -0
  199. data/test/contract/data/transaction_driven/delete.ex +29 -0
  200. data/test/contract/data/transaction_driven/direct_sql.ex +19 -0
  201. data/test/contract/data/transaction_driven/insert.ex +8 -0
  202. data/test/contract/data/transaction_driven/update.ex +19 -0
  203. data/test/contract/data/transaction_driven.spec +18 -0
  204. data/test/contract/robust/data/table_driven.spec +15 -0
  205. data/test/contract/robust/data/transaction_driven.spec +21 -0
  206. data/test/contract/robust/schema/table_driven.spec +21 -0
  207. data/test/contract/robust/schema/transaction_driven.spec +19 -0
  208. data/test/contract/schema/table_driven/column_names.ex +5 -0
  209. data/test/contract/schema/table_driven/has_column_q.ex +13 -0
  210. data/test/contract/schema/table_driven/has_table_q.ex +11 -0
  211. data/test/contract/schema/table_driven/heading.ex +5 -0
  212. data/test/contract/schema/table_driven.spec +9 -0
  213. data/test/contract/schema/transaction_driven/create_table.ex +10 -0
  214. data/test/contract/schema/transaction_driven/drop_table.ex +10 -0
  215. data/test/contract/schema/transaction_driven.spec +18 -0
  216. data/test/contract.spec +66 -0
  217. data/test/fixtures/basics/data/basic_values.rb +13 -0
  218. data/test/fixtures/basics/data/empty_table.rb +3 -0
  219. data/test/fixtures/basics/data/non_empty_table.rb +4 -0
  220. data/test/fixtures/basics/data/parts.rb +8 -0
  221. data/test/fixtures/basics/data/suppliers.rb +7 -0
  222. data/test/fixtures/basics/data/supplies.rb +14 -0
  223. data/test/fixtures/basics/dbagile.idx +20 -0
  224. data/test/fixtures/basics/fixtures.yaml +28 -0
  225. data/test/fixtures/basics/robust.db +0 -0
  226. data/test/fixtures/basics/suppliers.yaml +30 -0
  227. data/test/fixtures/basics/test.db +0 -0
  228. data/test/fixtures/empty/dbagile.idx +5 -0
  229. data/test/fixtures.rb +152 -0
  230. data/test/restful/delete/no_format.ex +32 -0
  231. data/test/restful/delete.spec +8 -0
  232. data/test/restful/get/csv_format.ex +12 -0
  233. data/test/restful/get/json_format.ex +19 -0
  234. data/test/restful/get/query_string.ex +11 -0
  235. data/test/restful/get/text_format.ex +12 -0
  236. data/test/restful/get/yaml_format.ex +14 -0
  237. data/test/restful/get.spec +5 -0
  238. data/test/restful/post/no_format.ex +22 -0
  239. data/test/restful/post.spec +8 -0
  240. data/test/restful.spec +32 -0
  241. data/test/run_all_suite.rb +51 -0
  242. data/test/spec_helper.rb +26 -0
  243. data/test/support/be_a_valid_json_string.rb +19 -0
  244. data/test/support/be_a_valid_yaml_string.rb +18 -0
  245. data/test/unit/adapter/factor.spec +13 -0
  246. data/test/unit/adapter/sequel/new.spec +19 -0
  247. data/test/unit/command/api.spec +12 -0
  248. data/test/unit/command/command_for.spec +36 -0
  249. data/test/unit/command/command_name_of.spec +21 -0
  250. data/test/unit/command/ruby_method_for.spec +21 -0
  251. data/test/unit/command/sanity.spec +34 -0
  252. data/test/unit/contract/utils/delegate/delegate.spec +23 -0
  253. data/test/unit/core/chain/chain.spec +57 -0
  254. data/test/unit/core/chain/connect.spec +22 -0
  255. data/test/unit/core/chain/delegate_chain.spec +16 -0
  256. data/test/unit/core/chain/initialize.spec +19 -0
  257. data/test/unit/core/chain/plug.spec +31 -0
  258. data/test/unit/core/io/dsl/scope.spec +9 -0
  259. data/test/unit/core/repository/create_bang.spec +31 -0
  260. data/test/unit/core/repository/current.spec +31 -0
  261. data/test/unit/core/repository/database.spec +47 -0
  262. data/test/unit/core/repository/fixtures/corrupted/dbagile.idx +1 -0
  263. data/test/unit/core/repository/fixtures/test_and_prod/dbagile.idx +21 -0
  264. data/test/unit/core/repository/fixtures.rb +25 -0
  265. data/test/unit/core/repository/has_database_q.spec +16 -0
  266. data/test/unit/core/repository/load.spec +51 -0
  267. data/test/unit/core/repository/to_yaml.spec +17 -0
  268. data/test/unit/core/schema/check.spec +32 -0
  269. data/test/unit/core/schema/empty_q.spec +18 -0
  270. data/test/unit/core/schema/filter.spec +42 -0
  271. data/test/unit/core/schema/fixtures/dbagile.yaml +7 -0
  272. data/test/unit/core/schema/fixtures/empty.yaml +11 -0
  273. data/test/unit/core/schema/fixtures/invalid.yaml +54 -0
  274. data/test/unit/core/schema/fixtures/left.yaml +46 -0
  275. data/test/unit/core/schema/fixtures/left_minus_right.yaml +31 -0
  276. data/test/unit/core/schema/fixtures/right.yaml +46 -0
  277. data/test/unit/core/schema/fixtures/right_minus_left.yaml +31 -0
  278. data/test/unit/core/schema/fixtures/suppliers_and_parts.yaml +30 -0
  279. data/test/unit/core/schema/fixtures.rb +32 -0
  280. data/test/unit/core/schema/merge.spec +72 -0
  281. data/test/unit/core/schema/minus.spec +26 -0
  282. data/test/unit/core/schema/sanity.spec +39 -0
  283. data/test/unit/core/schema/split.spec +58 -0
  284. data/test/unit/core/schema/stage_script.spec +26 -0
  285. data/test/unit/core/schema/to_yaml.spec +13 -0
  286. data/test/unit/core/schema/yaml_display.spec +14 -0
  287. data/test/unit/core/schema/yaml_load.spec +20 -0
  288. data/test/unit/core/transaction/transaction.spec +10 -0
  289. data/test/unit/fixtures.rb +67 -0
  290. data/test/unit/io/to_xxx.spec +52 -0
  291. data/test/unit/plugin/options.spec +21 -0
  292. data/test/unit/plugin/tuple_heading.spec +11 -0
  293. data/test/unit/plugin/with_options.spec +12 -0
  294. data/test/unit/tools/ruby/class_unqualified_name.spec +26 -0
  295. data/test/unit/tools/ruby/extract_file_rdoc.spec +10 -0
  296. data/test/unit/tools/ruby/fixtures/rdoc.txt +12 -0
  297. data/test/unit/tools/ruby/fixtures.rb +19 -0
  298. data/test/unit/tools/ruby/optional_args_block_call.spec +35 -0
  299. data/test/unit/tools/ruby/parent_module.spec +21 -0
  300. data/test/unit/tools/ruby/rdoc_file_paragraphs.spec +13 -0
  301. data/test/unit/tools/tuple/tuple_heading.spec +11 -0
  302. data/test/unit/tools/tuple/tuple_key.spec +27 -0
  303. data/test/unit/tools/tuple/tuple_project.spec +23 -0
  304. data/test/unit.spec +3 -0
  305. metadata +422 -0
@@ -0,0 +1,208 @@
1
+ module DbAgile
2
+ class Environment
3
+ #
4
+ # Environment's interactions contract.
5
+ #
6
+ module Interactions
7
+
8
+ # The buffer to use for displaying messages
9
+ attr_reader :message_buffer
10
+
11
+ # The buffer to use for asking questions
12
+ attr_reader :asking_buffer
13
+
14
+ ##############################################################################
15
+ ### Robustness
16
+ ##############################################################################
17
+
18
+ #
19
+ # Asserts that the interactive mode is enabled. Raises a
20
+ # InteractiveModeRequiredError otherwise.
21
+ #
22
+ def interactive!(msg = nil)
23
+ unless interactive?
24
+ msg = "The interactive mode is required, but disabled."
25
+ raise InteractiveModeRequiredError, msg
26
+ end
27
+ end
28
+
29
+ ##############################################################################
30
+ ### Configuration
31
+ ##############################################################################
32
+
33
+ #
34
+ # Returns true if the environment is interactive, false
35
+ # otherwise
36
+ #
37
+ def interactive?
38
+ @interactive
39
+ end
40
+
41
+ #
42
+ # Sets the interactive mode.
43
+ #
44
+ # In all cases, the highline instance for interaction is reset
45
+ # to nil.
46
+ #
47
+ def interactive=(value)
48
+ @interactive = value
49
+ @interaction_highline = nil
50
+ end
51
+
52
+ #
53
+ # Sets the message/output buffer to use for interactions.
54
+ #
55
+ # In all cases, the highline instance for interaction is reset
56
+ # to nil.
57
+ #
58
+ def message_buffer=(buffer)
59
+ @message_buffer = buffer
60
+ @interaction_highline = nil
61
+ end
62
+
63
+ #
64
+ # Sets the asking/input buffer to use for interactions.
65
+ #
66
+ # In all cases, the highline instance for interaction is reset
67
+ # to nil.
68
+ #
69
+ def asking_buffer=(buffer)
70
+ @asking_buffer = buffer
71
+ @interaction_highline = nil
72
+ end
73
+
74
+ ##############################################################################
75
+ ### HighLine delegation
76
+ ##############################################################################
77
+
78
+ #
79
+ # Returns an instance of HighLine for interactions, creating it
80
+ # if required.
81
+ #
82
+ # This method factors an HighLine instance even if interactive
83
+ # is set to false. Checking the interactive? flag should be made
84
+ # upstream.
85
+ #
86
+ def interaction_highline
87
+ if @interaction_highline.nil?
88
+ in_buffer = asking_buffer || input_buffer
89
+ out_buffer = message_buffer || output_buffer
90
+ @interaction_highline = HighLine.new(in_buffer, out_buffer)
91
+ end
92
+ @interaction_highline
93
+ end
94
+
95
+ #
96
+ # Asks something to the user/oracle and returns the result.
97
+ #
98
+ # This method is provided when something needs to be asked to the user.
99
+ # It simply returns non_interactive_value if the interaction flag is set
100
+ # to false. Otherwise, it delegates the call to the interaction highline
101
+ # instance.
102
+ #
103
+ # @param [String] question a prompt for the question
104
+ # @param [Proc] continuation a optional continuation procedure
105
+ # @param [...] non_interactive_value value to return in non-interactive
106
+ # mode
107
+ # @return [...] non_interactive_value in non-interactive mode, the result
108
+ # of continuation proc otherwise.
109
+ #
110
+ def ask(question, answer_type = String, non_interactive_value = nil, &continuation)
111
+ if interactive?
112
+ interaction_highline.ask(question, answer_type, &continuation)
113
+ else
114
+ nil
115
+ end
116
+ end
117
+
118
+ #
119
+ # Same specification as ask, but immediately raises an
120
+ # InteractiveModeRequiredError if the interactive mode is not set!
121
+ #
122
+ def ask!(question, answer_type = String, &continuation)
123
+ interactive!
124
+ ask(question, answer_type, nil, &continuation)
125
+ end
126
+
127
+ #
128
+ # Prints an information message on the appropriate buffer. An optional
129
+ # color may be provided if the environment supports colors.
130
+ #
131
+ # Does nothing when interactive mode is disabled. Delegates the call
132
+ # to highline otherwise.
133
+ #
134
+ # The something argument is expected to be a String. Use display to
135
+ # show complex objects, Enumerable in particular
136
+ #
137
+ # @param [String] something a message to print
138
+ # @param [Symbol] an optional color
139
+ # @return [void]
140
+ #
141
+ def say(something, color = nil)
142
+ if interactive?
143
+ h = interaction_highline
144
+ color.nil? ? h.say(something) : h.say(h.color(something, color))
145
+ end
146
+ end
147
+
148
+ #
149
+ # Displays something on the message buffer.
150
+ #
151
+ # Does nothing when interactive mode is disabled. Delegates the call
152
+ # to highline otherwise.
153
+ #
154
+ # @param [Object] something to write on environment output
155
+ # @return [void]
156
+ #
157
+ def display(something, color = nil)
158
+ if interactive?
159
+ if something.kind_of?(String)
160
+ say(something, color)
161
+ elsif something.kind_of?(Enumerable)
162
+ something.each{|v| display(v, color)}
163
+ else
164
+ display(something.to_s, color)
165
+ end
166
+ end
167
+ end
168
+
169
+ ##############################################################################
170
+ ### Console
171
+ ##############################################################################
172
+
173
+ #
174
+ # When interaction mode is set, colorizes a string with highline.
175
+ # Simply returns str otherwise.
176
+ #
177
+ def color(str, color)
178
+ interactive? ? interaction_highline.color(str, color) : str
179
+ end
180
+
181
+ #
182
+ # Forces the console width.
183
+ #
184
+ # When a width is set, it will always be returned by console_width, bypassing
185
+ # any attempt to use highline to infer it.
186
+ #
187
+ def console_width=(width)
188
+ @console_width = width
189
+ end
190
+
191
+ #
192
+ # Returns width of the console. Width set with console_width= is returned in
193
+ # priority. Otherwise, return highline's output_cols in interactive mode.
194
+ # Returns 80 in all other cases.
195
+ #
196
+ def console_width
197
+ @console_width ||= infer_console_width
198
+ end
199
+
200
+ # Tries to infer the console width
201
+ def infer_console_width
202
+ interactive? ? interaction_highline.output_cols-3 : 80
203
+ end
204
+
205
+ private :infer_console_width
206
+ end # module Interactions
207
+ end # class Environment
208
+ end # module DbAgile
@@ -0,0 +1,47 @@
1
+ module DbAgile
2
+ class Environment
3
+ module OnError
4
+
5
+ # Show backtrace on errors?
6
+ attr_writer :show_backtrace
7
+
8
+ # Shows the backtrace when an error occurs?
9
+ def show_backtrace?
10
+ @show_backtrace
11
+ end
12
+
13
+ #
14
+ # Handles an error that occured during command execution.
15
+ #
16
+ # @param [Exception] error the error that was raised
17
+ # @return nil to continue execution, an error to raise otherwise
18
+ #
19
+ def on_error(command, error)
20
+ case error
21
+ when SystemExit
22
+ when OptionParser::ParseError
23
+ say(error.message, :red)
24
+ display(command.options.to_s)
25
+ when Sequel::Error, IOError
26
+ say(error.message, :red)
27
+ when DbAgile::SchemaSemanticsError
28
+ say(error.message(true), :red)
29
+ when DbAgile::InternalError
30
+ say("DbAgile encountered an internal error.\n Please replay with dba --backtrace and report the error!", :red)
31
+ say(error.message, :red)
32
+ when DbAgile::Error
33
+ say(error.message, :red)
34
+ when Interrupt
35
+ say("Command interrupted by user", :magenta)
36
+ else
37
+ say("ERROR (#{error.class}): #{error.message}", :red)
38
+ end
39
+ if show_backtrace?
40
+ say(error.backtrace.join("\n"))
41
+ end
42
+ error
43
+ end
44
+
45
+ end # module OnError
46
+ end # class Environment
47
+ end # module DbAgile
@@ -0,0 +1,161 @@
1
+ module DbAgile
2
+ class Environment
3
+ module Repository
4
+
5
+ #
6
+ # Checks if the repository exists or should be created.
7
+ #
8
+ # If the repository is currently loaded, this method returns true.
9
+ # Otherwise it returns true if the repository path exists. Note that
10
+ # repository consistency itself (index file) is not checked. You have
11
+ # to load it and catch exception to have a finer grained info.
12
+ #
13
+ def repository_exists?
14
+ return true if @repository
15
+ File.exists?(repository_path)
16
+ end
17
+
18
+ #
19
+ # Returns a friendly path for the repository, to display to the user.
20
+ # If a repository is loaded, the call is delegated. Otherwise, the
21
+ # repository_path is displayed, without attempting to load repository.
22
+ #
23
+ def friendly_repository_path
24
+ if @repository
25
+ @repository.friendly_path
26
+ else
27
+ DbAgile::FileSystemTools::friendly_path!(repository_path)
28
+ end
29
+ end
30
+
31
+ #
32
+ # Returns path to the repository
33
+ #
34
+ def repository_path
35
+ @repository_path
36
+ end
37
+
38
+ #
39
+ # Sets the path to the .dbagile file
40
+ #
41
+ def repository_path=(path)
42
+ @repository = nil
43
+ @repository_path = path
44
+ end
45
+
46
+ #
47
+ # Ensures that repository is loaded and returns the Repository instance.
48
+ #
49
+ # ATTENTION: the Repository instance is kept in cache. It will not be
50
+ # synchronized with modifications of the underlying files made by another
51
+ # process/thread.
52
+ #
53
+ # @raise IOError if the repository does not exists or something goes wrong
54
+ # with repository dir/files
55
+ # @raise CorruptedRepositoryError if something goes wrong when parsing the
56
+ # repository index file
57
+ # @return [Repository] repository instance
58
+ # @see DbAgile::Core::Repository::load
59
+ #
60
+ def repository
61
+ @repository ||= DbAgile::Core::Repository::load(repository_path)
62
+ end
63
+
64
+ #
65
+ # Yields the block with each database in turn
66
+ #
67
+ # As this method is a wrapper on repository, it shares the specification
68
+ # about exceptions.
69
+ #
70
+ # @raise ArgumentError if no block is provided
71
+ #
72
+ def each_database(&block)
73
+ raise ArgumentError, "Missing block" unless block_given?
74
+ repository.each(&block)
75
+ end
76
+
77
+ #
78
+ # Yields the block with the Repository instance (loaded using repository)
79
+ #
80
+ # As this method is a wrapper on repository, it shares the specification
81
+ # about exceptions.
82
+ #
83
+ # @return [...] result of the block execution
84
+ # @raise ArgumentError if no block is provided
85
+ #
86
+ def with_repository
87
+ raise ArgumentError, "Missing block" unless block_given?
88
+ yield(repository)
89
+ end
90
+
91
+ #
92
+ # Yields the block with a Database instance found by name in the
93
+ # repository
94
+ #
95
+ # As this method relies on repository, it shares its exception contract.
96
+ #
97
+ # @raise ArgumentError if no block is provided
98
+ # @raise NoSuchDatabaseError if the database cannot be found.
99
+ # @return block execution result
100
+ #
101
+ def with_database(name)
102
+ raise ArgumentError, "Missing block" unless block_given?
103
+ db = repository.database(name)
104
+ raise NoSuchDatabaseError if db.nil?
105
+ yield(db)
106
+ end
107
+
108
+ #
109
+ # Yields the block with the Database instance for the current one
110
+ # in repository.
111
+ #
112
+ # As this method relies on repository, it shares its exception contract.
113
+ #
114
+ # @raise ArgumentError if no block is provided
115
+ # @raise NoDefaultDatabaseError if the database cannot be found.
116
+ # @return block execution result
117
+ #
118
+ def with_current_database
119
+ raise ArgumentError, "Missing block" unless block_given?
120
+ db = repository.current_database
121
+ raise NoDefaultDatabaseError if db.nil?
122
+ yield(db)
123
+ end
124
+
125
+ #
126
+ # Yields the block with a connection on a given database; diconnect after that.
127
+ #
128
+ # As this method relies on repository, it shares its exception contract.
129
+ #
130
+ # @raise ArgumentError if no block is provided
131
+ # @raise NoSuchDatabaseError if the database cannot be found.
132
+ # @return block execution result
133
+ #
134
+ def with_connection(db, conn_options = {}, &block)
135
+ case db
136
+ when Symbol
137
+ db = repository.database(db)
138
+ when DbAgile::Core::Database
139
+ else
140
+ raise ArgumentError, "Invalid database name #{db}"
141
+ end
142
+ raise NoSuchDatabaseError if db.nil?
143
+ db.with_connection(&block)
144
+ end
145
+
146
+ #
147
+ # Yields the block with a connection on the current database.
148
+ #
149
+ # Same contract as with_connection, expect for parameters.
150
+ #
151
+ # @raise NoDefaultDatabaseError if the database cannot be found.
152
+ #
153
+ def with_current_connection(conn_options = {}, &block)
154
+ with_current_database{|db|
155
+ with_connection(db, conn_options, &block)
156
+ }
157
+ end
158
+
159
+ end # module Repository
160
+ end # class Environment
161
+ end # module DbAgile
@@ -0,0 +1,7 @@
1
+ module DbAgile
2
+
3
+ # Raised when the interactive mode is definitely required,
4
+ # but set to false
5
+ class InteractiveModeRequiredError < DbAgile::Error; end
6
+
7
+ end # module DbAgile
@@ -0,0 +1,23 @@
1
+ module DbAgile
2
+ class Environment
3
+ module Testing
4
+
5
+ # Returns the output buffer as a string
6
+ def output_buffer_str
7
+ if self.output_buffer.kind_of?(StringIO)
8
+ output_buffer.string
9
+ else
10
+ raise DbAgile::AssumptionFailedError, "StringIO expected as output buffer"
11
+ end
12
+ end
13
+
14
+ #
15
+ # Returns true if the current output buffer matches a regular expression
16
+ #
17
+ def has_flushed?(rx)
18
+ (self.output_buffer_str =~ rx) ? true : false
19
+ end
20
+
21
+ end # module Testing
22
+ end # class Environment
23
+ end # module DbAgile
@@ -0,0 +1,122 @@
1
+ require 'dbagile/environment/robustness'
2
+ require 'dbagile/environment/on_error'
3
+ require 'dbagile/environment/buffering'
4
+ require 'dbagile/environment/interactions'
5
+ require 'dbagile/environment/repository'
6
+ require 'dbagile/environment/delegator'
7
+ module DbAgile
8
+ #
9
+ # Defines the contract to be an environment for dbagile.
10
+ #
11
+ class Environment
12
+ include DbAgile::Environment::OnError
13
+ include DbAgile::Environment::Buffering
14
+ include DbAgile::Environment::Interactions
15
+ include DbAgile::Environment::Repository
16
+
17
+ #
18
+ # Installs the testing methods, StringIO on output buffers then
19
+ # returns self
20
+ #
21
+ def with_testing_methods!(interactive = true)
22
+ require 'dbagile/environment/testing'
23
+ extend(DbAgile::Environment::Testing)
24
+ self.output_buffer = StringIO.new
25
+ self.message_buffer = StringIO.new
26
+ self.interactive = interactive
27
+ self
28
+ end
29
+
30
+ #
31
+ # Creates a default Environment instance with following options:
32
+ #
33
+ # - repository_path -> what Environment::default_repository_path returns
34
+ # - input_buffer -> STDIN
35
+ # - output_buffer -> STDOUT
36
+ # - interactive? -> true
37
+ # - asking_buffer -> STDIN
38
+ # - message_buffer -> STDERR
39
+ # - show_backtrace -> false
40
+ #
41
+ def initialize
42
+ @repository_path = Environment::default_repository_path
43
+ @input_buffer = STDIN
44
+ @output_buffer = STDOUT
45
+ @interactive = true
46
+ @asking_buffer = STDIN
47
+ @message_buffer = STDERR
48
+ @show_backtrace = false
49
+ end
50
+
51
+ #
52
+ # Duplicates the environment but removes any cached value (repository
53
+ # and so on)
54
+ #
55
+ def dup
56
+ env = Environment.new
57
+ env.repository_path = self.repository_path
58
+ env.input_buffer = self.input_buffer
59
+ env.output_buffer = self.output_buffer
60
+ env.interactive = self.interactive?
61
+ env.asking_buffer = self.asking_buffer
62
+ env.message_buffer = self.message_buffer
63
+ env.show_backtrace = self.show_backtrace?
64
+ env
65
+ end
66
+
67
+ #
68
+ # Returns the default path to use for a repository.
69
+ #
70
+ # The algorithm implemented tries to locate a repository folder in the
71
+ # following order:
72
+ #
73
+ # - dbagile.idx file in the current directory -> it's parent folder
74
+ # - dbagile folder in the current directory -> ./dbagile
75
+ # - .dbagile folder in user's home -> ~/.dbagile
76
+ #
77
+ # If none of those files exists, ~/.dbagile is returned
78
+ #
79
+ def self.default_repository_path
80
+ if File.exists?("./dbagile.idx")
81
+ "."
82
+ elsif File.exists?("dbagile")
83
+ "dbagile"
84
+ else
85
+ File.join(ENV['HOME'], '.dbagile')
86
+ end
87
+ end
88
+
89
+ #
90
+ # Returns the default environment to use.
91
+ #
92
+ # The algorithm implemented tries to locate a repository folder in the
93
+ # following order:
94
+ #
95
+ # - dbagile.idx file in the current directory -> it's parent folder
96
+ # - dbagile folder in the current directory -> ./dbagile
97
+ # - .dbagile folder in user's home -> ~/.dbagile
98
+ #
99
+ # If none of those files exists, a default environment will be created
100
+ # mapping to an unexisting repository folder in ~/.dbagile
101
+ #
102
+ # By default, the repository is not loaded at all, and errors can therefore
103
+ # occur later, when the repository will be first accessed. Set
104
+ # load_repository to true to force immediate load.
105
+ #
106
+ def self.default(load_repository = false)
107
+ env = Environment.new
108
+ if load_repository
109
+ env.repository
110
+ end
111
+ env
112
+ end
113
+
114
+ #
115
+ # Convenient method for Environment::default(true)
116
+ #
117
+ def self.default!
118
+ Environment::default(true)
119
+ end
120
+
121
+ end # class Environment
122
+ end # module DbAgile
@@ -0,0 +1,30 @@
1
+ module DbAgile
2
+
3
+ # Raised when a database name is not valid
4
+ class InvalidDatabaseName < DbAgile::Error; end
5
+
6
+ # Raised when a database URI is not valid
7
+ class InvalidDatabaseUri < DbAgile::Error; end
8
+
9
+ # Raised when a command does not exists (dba command line tool)
10
+ class NoSuchCommandError < DbAgile::Error; end
11
+
12
+ # Raised when the repository seems corrupted
13
+ class CorruptedRepositoryError < DbAgile::Error; end
14
+
15
+ # Raised when a database cannot be found
16
+ class NoSuchDatabaseError < DbAgile::Error; end
17
+
18
+ # Raised when a database name is already used (on add)
19
+ class DatabaseNameConflictError < DbAgile::Error; end
20
+
21
+ # Raised when no default database is set
22
+ class NoDefaultDatabaseError < DbAgile::Error; end
23
+
24
+ # Raised when input parsing of data fails for some reason
25
+ class InvalidFormatError < DbAgile::Error; end
26
+
27
+ # Raised when usage of schema files fails because they are not installed
28
+ class NoSchemaFilesError < DbAgile::Error; end
29
+
30
+ end # module DbAgile
@@ -0,0 +1,99 @@
1
+ module DbAgile
2
+ module IO
3
+ module CSV
4
+ extend IO::TypeSafe
5
+
6
+ # Normalizes CSV options from DBAgile options
7
+ def normalize_options(options)
8
+ if options[:type_system]
9
+ options[:headers] = true unless options.key?(:headers)
10
+ options[:quote_char] = "'" unless options.key?(:quote_char)
11
+ options[:force_quotes] = true unless options.key?(:force_quotes)
12
+ end
13
+ if options[:headers]
14
+ options[:write_headers] = true
15
+ options[:return_headers] = true
16
+ end
17
+ options
18
+ end
19
+ module_function :normalize_options
20
+
21
+ # Makes the CSV require, depending on Ruby version
22
+ def build_csv_instance(io, options)
23
+ if RUBY_VERSION >= "1.9.0"
24
+ require 'csv'
25
+ options = normalize_options(options)
26
+ csv_options = options.dup.delete_if{|key,value| !::CSV::DEFAULT_OPTIONS.key?(key)}
27
+ [::CSV.new(io, csv_options), options]
28
+ else
29
+ require 'faster_csv'
30
+ options = normalize_options(options)
31
+ csv_options = options.dup.delete_if{|key,value| !FasterCSV::DEFAULT_OPTIONS.key?(key)}
32
+ [FasterCSV.new(io, csv_options), options]
33
+ end
34
+ end
35
+ module_function :build_csv_instance
36
+
37
+ #
38
+ # Outputs some data as a CSV string.
39
+ #
40
+ # @return [...] the buffer itself
41
+ #
42
+ def to_csv(data, columns, buffer = "", options = {})
43
+ # Creates a CSV outputter with options
44
+ csv, options = build_csv_instance(buffer, options)
45
+
46
+ # Write header if required
47
+ if options[:headers]
48
+ if ts = options[:type_system]
49
+ csv << columns.collect{|c| ts.to_literal(c)}
50
+ else
51
+ csv << columns
52
+ end
53
+ end
54
+
55
+ # Write tuples now
56
+ with_type_safe_relation(data, options) do |tuple|
57
+ csv << columns.collect{|c| tuple[c]}
58
+ end
59
+
60
+ # Return buffer
61
+ buffer
62
+ end
63
+ module_function :to_csv
64
+
65
+ #
66
+ # If a block is given yields it with each tuple that can be loaded from
67
+ # the CSV input and returns nil. Otherwise, reads the CSV input and returns
68
+ # an array of tuples.
69
+ #
70
+ def from_csv(input, options = {})
71
+ # Creates a CSV inputer with options
72
+ csv, options = build_csv_instance(input, options)
73
+ if ts = options[:type_system]
74
+ converter = lambda{|field| ts.parse_literal(field)}
75
+ csv.header_convert(&converter)
76
+ csv.convert(&converter)
77
+ end
78
+
79
+ # Load data now
80
+ ts = options[:type_system]
81
+ if block_given?
82
+ csv.each do |row|
83
+ next if row.header_row?
84
+ yield(row.to_hash)
85
+ end
86
+ else
87
+ tuples = []
88
+ csv.each do |row|
89
+ next if row.header_row?
90
+ tuples << row.to_hash
91
+ end
92
+ tuples
93
+ end
94
+ end
95
+ module_function :from_csv
96
+
97
+ end # module CSVTools
98
+ end # module IO
99
+ end # module DbAgile