alf 0.12.2 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (549) hide show
  1. data/CHANGELOG.md +186 -80
  2. data/Gemfile +16 -32
  3. data/Gemfile.lock +35 -34
  4. data/LICENCE.md +1 -1
  5. data/Manifest.txt +7 -9
  6. data/README.md +139 -809
  7. data/alf.gemspec +6 -15
  8. data/alf.noespec +16 -34
  9. data/lib/alf.rb +3 -73
  10. data/lib/alf/loader.rb +3 -3
  11. data/lib/alf/version.rb +2 -2
  12. data/spec/spec_helper.rb +3 -18
  13. data/spec/test_alf.rb +8 -0
  14. data/tasks/test.rake +6 -0
  15. data/test/migrations/test_folder_migration.rb +18 -0
  16. data/test/migrations/test_sequel_migration.rb +34 -0
  17. data/test/seeding/test_seeding.rb +49 -0
  18. data/test/test_alf.rb +8 -0
  19. data/test/test_helpers.rb +24 -0
  20. metadata +54 -952
  21. data/TODO.md +0 -21
  22. data/bin/alf +0 -27
  23. data/doc/commands/exec.md +0 -16
  24. data/doc/commands/help.md +0 -11
  25. data/doc/commands/main.md +0 -33
  26. data/doc/commands/show.md +0 -19
  27. data/doc/operators/non_relational/autonum.md +0 -23
  28. data/doc/operators/non_relational/clip.md +0 -31
  29. data/doc/operators/non_relational/coerce.md +0 -15
  30. data/doc/operators/non_relational/compact.md +0 -20
  31. data/doc/operators/non_relational/defaults.md +0 -32
  32. data/doc/operators/non_relational/generator.md +0 -20
  33. data/doc/operators/non_relational/sort.md +0 -24
  34. data/doc/operators/relational/extend.md +0 -18
  35. data/doc/operators/relational/group.md +0 -27
  36. data/doc/operators/relational/heading.md +0 -20
  37. data/doc/operators/relational/intersect.md +0 -13
  38. data/doc/operators/relational/join.md +0 -28
  39. data/doc/operators/relational/matching.md +0 -24
  40. data/doc/operators/relational/minus.md +0 -12
  41. data/doc/operators/relational/not-matching.md +0 -20
  42. data/doc/operators/relational/project.md +0 -28
  43. data/doc/operators/relational/quota.md +0 -21
  44. data/doc/operators/relational/rank.md +0 -27
  45. data/doc/operators/relational/rename.md +0 -17
  46. data/doc/operators/relational/restrict.md +0 -25
  47. data/doc/operators/relational/summarize.md +0 -25
  48. data/doc/operators/relational/ungroup.md +0 -20
  49. data/doc/operators/relational/union.md +0 -14
  50. data/doc/operators/relational/unwrap.md +0 -20
  51. data/doc/operators/relational/wrap.md +0 -24
  52. data/examples/csv/suppliers.csv +0 -6
  53. data/examples/logs/access.log +0 -1000
  54. data/examples/logs/combined.alf +0 -2
  55. data/examples/logs/hits.alf +0 -14
  56. data/examples/logs/not_found.alf +0 -7
  57. data/examples/logs/robots-cheating.alf +0 -11
  58. data/examples/logs/robots.alf +0 -8
  59. data/examples/operators/autonum.alf +0 -6
  60. data/examples/operators/cities.rash +0 -4
  61. data/examples/operators/clip.alf +0 -3
  62. data/examples/operators/compact.alf +0 -2
  63. data/examples/operators/database.alf +0 -5
  64. data/examples/operators/defaults.alf +0 -3
  65. data/examples/operators/extend.alf +0 -3
  66. data/examples/operators/group.alf +0 -3
  67. data/examples/operators/intersect.alf +0 -4
  68. data/examples/operators/join.alf +0 -2
  69. data/examples/operators/matching.alf +0 -2
  70. data/examples/operators/minus.alf +0 -8
  71. data/examples/operators/not_matching.alf +0 -2
  72. data/examples/operators/nulls.rash +0 -3
  73. data/examples/operators/parts.rash +0 -6
  74. data/examples/operators/project.alf +0 -3
  75. data/examples/operators/pseudo-with.alf +0 -7
  76. data/examples/operators/quota.alf +0 -4
  77. data/examples/operators/rank.alf +0 -4
  78. data/examples/operators/rename.alf +0 -3
  79. data/examples/operators/restrict.alf +0 -2
  80. data/examples/operators/schema.yaml +0 -28
  81. data/examples/operators/sort.alf +0 -4
  82. data/examples/operators/summarize.alf +0 -16
  83. data/examples/operators/suppliers.rash +0 -5
  84. data/examples/operators/supplies.rash +0 -12
  85. data/examples/operators/ungroup.alf +0 -4
  86. data/examples/operators/union.alf +0 -3
  87. data/examples/operators/unwrap.alf +0 -4
  88. data/examples/operators/wrap.alf +0 -2
  89. data/lib/alf-csv/alf/csv.rb +0 -3
  90. data/lib/alf-csv/alf/csv/commons.rb +0 -36
  91. data/lib/alf-csv/alf/csv/reader.rb +0 -33
  92. data/lib/alf-csv/alf/csv/renderer.rb +0 -38
  93. data/lib/alf-engine/alf/engine.rb +0 -25
  94. data/lib/alf-engine/alf/engine/aggregate.rb +0 -44
  95. data/lib/alf-engine/alf/engine/autonum.rb +0 -45
  96. data/lib/alf-engine/alf/engine/cesure.rb +0 -45
  97. data/lib/alf-engine/alf/engine/clip.rb +0 -53
  98. data/lib/alf-engine/alf/engine/coerce.rb +0 -46
  99. data/lib/alf-engine/alf/engine/cog.rb +0 -7
  100. data/lib/alf-engine/alf/engine/compact.rb +0 -26
  101. data/lib/alf-engine/alf/engine/compact/set.rb +0 -23
  102. data/lib/alf-engine/alf/engine/compact/uniq.rb +0 -23
  103. data/lib/alf-engine/alf/engine/concat.rb +0 -25
  104. data/lib/alf-engine/alf/engine/defaults.rb +0 -43
  105. data/lib/alf-engine/alf/engine/filter.rb +0 -41
  106. data/lib/alf-engine/alf/engine/generator.rb +0 -50
  107. data/lib/alf-engine/alf/engine/group.rb +0 -7
  108. data/lib/alf-engine/alf/engine/group/hash.rb +0 -40
  109. data/lib/alf-engine/alf/engine/join.rb +0 -7
  110. data/lib/alf-engine/alf/engine/join/hash.rb +0 -35
  111. data/lib/alf-engine/alf/engine/materialize.rb +0 -8
  112. data/lib/alf-engine/alf/engine/materialize/array.rb +0 -78
  113. data/lib/alf-engine/alf/engine/materialize/hash.rb +0 -122
  114. data/lib/alf-engine/alf/engine/quota.rb +0 -7
  115. data/lib/alf-engine/alf/engine/quota/cesure.rb +0 -46
  116. data/lib/alf-engine/alf/engine/rank.rb +0 -7
  117. data/lib/alf-engine/alf/engine/rank/cesure.rb +0 -48
  118. data/lib/alf-engine/alf/engine/rename.rb +0 -39
  119. data/lib/alf-engine/alf/engine/semi.rb +0 -7
  120. data/lib/alf-engine/alf/engine/semi/hash.rb +0 -39
  121. data/lib/alf-engine/alf/engine/set_attr.rb +0 -46
  122. data/lib/alf-engine/alf/engine/sort.rb +0 -28
  123. data/lib/alf-engine/alf/engine/sort/in_memory.rb +0 -39
  124. data/lib/alf-engine/alf/engine/summarize.rb +0 -8
  125. data/lib/alf-engine/alf/engine/summarize/cesure.rb +0 -51
  126. data/lib/alf-engine/alf/engine/summarize/hash.rb +0 -35
  127. data/lib/alf-engine/alf/engine/ungroup.rb +0 -29
  128. data/lib/alf-engine/alf/engine/unwrap.rb +0 -31
  129. data/lib/alf-engine/alf/engine/wrap.rb +0 -39
  130. data/lib/alf-logs/alf/logs.rb +0 -1
  131. data/lib/alf-logs/alf/logs/reader.rb +0 -98
  132. data/lib/alf-sequel/alf/sequel.rb +0 -2
  133. data/lib/alf-sequel/alf/sequel/environment.rb +0 -61
  134. data/lib/alf-sequel/alf/sequel/iterator.rb +0 -21
  135. data/lib/alf-shell/alf/shell.rb +0 -40
  136. data/lib/alf-shell/alf/shell/command.rb +0 -26
  137. data/lib/alf-shell/alf/shell/command/exec.rb +0 -11
  138. data/lib/alf-shell/alf/shell/command/help.rb +0 -30
  139. data/lib/alf-shell/alf/shell/command/main.rb +0 -136
  140. data/lib/alf-shell/alf/shell/command/main/class_methods.rb +0 -46
  141. data/lib/alf-shell/alf/shell/command/show.rb +0 -63
  142. data/lib/alf-shell/alf/shell/doc_manager.rb +0 -72
  143. data/lib/alf-shell/alf/shell/operator.rb +0 -86
  144. data/lib/alf-yaml/alf/yaml.rb +0 -1
  145. data/lib/alf-yaml/alf/yaml/renderer.rb +0 -22
  146. data/lib/alf/aggregator.rb +0 -51
  147. data/lib/alf/aggregator/avg.rb +0 -39
  148. data/lib/alf/aggregator/class_methods.rb +0 -77
  149. data/lib/alf/aggregator/collect.rb +0 -32
  150. data/lib/alf/aggregator/concat.rb +0 -47
  151. data/lib/alf/aggregator/count.rb +0 -32
  152. data/lib/alf/aggregator/instance_methods.rb +0 -119
  153. data/lib/alf/aggregator/max.rb +0 -32
  154. data/lib/alf/aggregator/min.rb +0 -32
  155. data/lib/alf/aggregator/stddev.rb +0 -25
  156. data/lib/alf/aggregator/sum.rb +0 -32
  157. data/lib/alf/aggregator/variance.rb +0 -45
  158. data/lib/alf/environment.rb +0 -34
  159. data/lib/alf/environment/class_methods.rb +0 -95
  160. data/lib/alf/environment/folder.rb +0 -60
  161. data/lib/alf/environment/instance_methods.rb +0 -26
  162. data/lib/alf/errors.rb +0 -5
  163. data/lib/alf/ext.rb +0 -4
  164. data/lib/alf/ext/relation.rb +0 -4
  165. data/lib/alf/iterator.rb +0 -28
  166. data/lib/alf/iterator/class_methods.rb +0 -20
  167. data/lib/alf/iterator/proxy.rb +0 -27
  168. data/lib/alf/lispy.rb +0 -24
  169. data/lib/alf/lispy/instance_methods.rb +0 -157
  170. data/lib/alf/operator.rb +0 -68
  171. data/lib/alf/operator/binary.rb +0 -21
  172. data/lib/alf/operator/class_methods.rb +0 -82
  173. data/lib/alf/operator/experimental.rb +0 -9
  174. data/lib/alf/operator/instance_methods.rb +0 -29
  175. data/lib/alf/operator/non_relational/autonum.rb +0 -19
  176. data/lib/alf/operator/non_relational/clip.rb +0 -20
  177. data/lib/alf/operator/non_relational/coerce.rb +0 -19
  178. data/lib/alf/operator/non_relational/compact.rb +0 -18
  179. data/lib/alf/operator/non_relational/defaults.rb +0 -22
  180. data/lib/alf/operator/non_relational/generator.rb +0 -20
  181. data/lib/alf/operator/non_relational/sort.rb +0 -19
  182. data/lib/alf/operator/nullary.rb +0 -11
  183. data/lib/alf/operator/relational/extend.rb +0 -19
  184. data/lib/alf/operator/relational/group.rb +0 -21
  185. data/lib/alf/operator/relational/heading.rb +0 -20
  186. data/lib/alf/operator/relational/intersect.rb +0 -18
  187. data/lib/alf/operator/relational/join.rb +0 -18
  188. data/lib/alf/operator/relational/matching.rb +0 -18
  189. data/lib/alf/operator/relational/minus.rb +0 -18
  190. data/lib/alf/operator/relational/not_matching.rb +0 -18
  191. data/lib/alf/operator/relational/project.rb +0 -22
  192. data/lib/alf/operator/relational/quota.rb +0 -23
  193. data/lib/alf/operator/relational/rank.rb +0 -22
  194. data/lib/alf/operator/relational/rename.rb +0 -18
  195. data/lib/alf/operator/relational/restrict.rb +0 -18
  196. data/lib/alf/operator/relational/summarize.rb +0 -27
  197. data/lib/alf/operator/relational/ungroup.rb +0 -19
  198. data/lib/alf/operator/relational/union.rb +0 -20
  199. data/lib/alf/operator/relational/unwrap.rb +0 -19
  200. data/lib/alf/operator/relational/wrap.rb +0 -20
  201. data/lib/alf/operator/signature.rb +0 -233
  202. data/lib/alf/operator/unary.rb +0 -16
  203. data/lib/alf/reader.rb +0 -37
  204. data/lib/alf/reader/alf_file.rb +0 -24
  205. data/lib/alf/reader/class_methods.rb +0 -91
  206. data/lib/alf/reader/instance_methods.rb +0 -97
  207. data/lib/alf/reader/rash.rb +0 -28
  208. data/lib/alf/relation.rb +0 -28
  209. data/lib/alf/relation/class_methods.rb +0 -28
  210. data/lib/alf/relation/instance_methods.rb +0 -119
  211. data/lib/alf/renderer.rb +0 -32
  212. data/lib/alf/renderer/class_methods.rb +0 -58
  213. data/lib/alf/renderer/instance_methods.rb +0 -55
  214. data/lib/alf/renderer/rash.rb +0 -33
  215. data/lib/alf/renderer/text.rb +0 -198
  216. data/lib/alf/tools.rb +0 -15
  217. data/lib/alf/tools/coerce.rb +0 -25
  218. data/lib/alf/tools/miscellaneous.rb +0 -111
  219. data/lib/alf/tools/to_lispy.rb +0 -96
  220. data/lib/alf/tools/to_relation.rb +0 -54
  221. data/lib/alf/tools/to_ruby_literal.rb +0 -31
  222. data/lib/alf/tools/tuple_handle.rb +0 -60
  223. data/lib/alf/types.rb +0 -49
  224. data/lib/alf/types/attr_list.rb +0 -160
  225. data/lib/alf/types/attr_name.rb +0 -66
  226. data/lib/alf/types/boolean.rb +0 -25
  227. data/lib/alf/types/heading.rb +0 -135
  228. data/lib/alf/types/ordering.rb +0 -146
  229. data/lib/alf/types/renaming.rb +0 -97
  230. data/lib/alf/types/size.rb +0 -57
  231. data/lib/alf/types/summarization.rb +0 -138
  232. data/lib/alf/types/tuple_computation.rb +0 -136
  233. data/lib/alf/types/tuple_expression.rb +0 -152
  234. data/lib/alf/types/tuple_predicate.rb +0 -73
  235. data/spec/integration/__database__/group.alf +0 -3
  236. data/spec/integration/__database__/parts.rash +0 -6
  237. data/spec/integration/__database__/suppliers.rash +0 -5
  238. data/spec/integration/__database__/suppliers_csv.csv +0 -6
  239. data/spec/integration/__database__/supplies.rash +0 -12
  240. data/spec/integration/alf/example.rash +0 -1
  241. data/spec/integration/alf/test_Relation.rb +0 -32
  242. data/spec/integration/ext/test_relation.rb +0 -16
  243. data/spec/integration/lispy/test_relation.rb +0 -37
  244. data/spec/integration/lispy/test_run.rb +0 -40
  245. data/spec/integration/lispy/test_tuple.rb +0 -36
  246. data/spec/integration/semantics/test_join.alf +0 -9
  247. data/spec/integration/semantics/test_minus.alf +0 -5
  248. data/spec/integration/semantics/test_project.alf +0 -8
  249. data/spec/integration/semantics/test_rank.alf +0 -34
  250. data/spec/integration/shell/alf/alf.db +0 -0
  251. data/spec/integration/shell/alf/alf_e.cmd +0 -1
  252. data/spec/integration/shell/alf/alf_e.stdout +0 -4
  253. data/spec/integration/shell/alf/alf_env.cmd +0 -1
  254. data/spec/integration/shell/alf/alf_env.stdout +0 -5
  255. data/spec/integration/shell/alf/alf_env_sqlite.cmd +0 -1
  256. data/spec/integration/shell/alf/alf_env_sqlite.stdout +0 -9
  257. data/spec/integration/shell/alf/alf_help.cmd +0 -1
  258. data/spec/integration/shell/alf/alf_help.stdout +0 -69
  259. data/spec/integration/shell/alf/alf_implicit.alf +0 -1
  260. data/spec/integration/shell/alf/alf_implicit_exec.cmd +0 -1
  261. data/spec/integration/shell/alf/alf_implicit_exec.stdout +0 -4
  262. data/spec/integration/shell/alf/alf_r.cmd +0 -1
  263. data/spec/integration/shell/alf/alf_r.stdout +0 -5
  264. data/spec/integration/shell/alf/alf_version.cmd +0 -1
  265. data/spec/integration/shell/alf/alf_version.stdout +0 -2
  266. data/spec/integration/shell/alf/alf_yaml.cmd +0 -1
  267. data/spec/integration/shell/alf/alf_yaml.stdout +0 -22
  268. data/spec/integration/shell/alf/rel.rash +0 -1
  269. data/spec/integration/shell/autonum/autonum_0.cmd +0 -1
  270. data/spec/integration/shell/autonum/autonum_0.stdout +0 -9
  271. data/spec/integration/shell/autonum/autonum_1.cmd +0 -1
  272. data/spec/integration/shell/autonum/autonum_1.stdout +0 -9
  273. data/spec/integration/shell/clip/clip_0.cmd +0 -1
  274. data/spec/integration/shell/clip/clip_0.stdout +0 -9
  275. data/spec/integration/shell/clip/clip_1.cmd +0 -1
  276. data/spec/integration/shell/clip/clip_1.stdout +0 -9
  277. data/spec/integration/shell/coerce/coerce_1.cmd +0 -1
  278. data/spec/integration/shell/coerce/coerce_1.stdout +0 -5
  279. data/spec/integration/shell/compact/compact_0.cmd +0 -1
  280. data/spec/integration/shell/compact/compact_0.stdout +0 -9
  281. data/spec/integration/shell/defaults/defaults_0.cmd +0 -1
  282. data/spec/integration/shell/defaults/defaults_0.stdout +0 -9
  283. data/spec/integration/shell/defaults/defaults_1.cmd +0 -1
  284. data/spec/integration/shell/defaults/defaults_1.stdout +0 -9
  285. data/spec/integration/shell/defaults/defaults_2.cmd +0 -1
  286. data/spec/integration/shell/defaults/defaults_2.stdout +0 -9
  287. data/spec/integration/shell/extend/extend_0.cmd +0 -1
  288. data/spec/integration/shell/extend/extend_0.stdout +0 -16
  289. data/spec/integration/shell/generator/generator_1.cmd +0 -1
  290. data/spec/integration/shell/generator/generator_1.stdout +0 -10
  291. data/spec/integration/shell/generator/generator_2.cmd +0 -1
  292. data/spec/integration/shell/generator/generator_2.stdout +0 -5
  293. data/spec/integration/shell/generator/generator_3.cmd +0 -1
  294. data/spec/integration/shell/generator/generator_3.stdout +0 -5
  295. data/spec/integration/shell/group/group_0.cmd +0 -1
  296. data/spec/integration/shell/group/group_0.stdout +0 -32
  297. data/spec/integration/shell/group/group_1.cmd +0 -1
  298. data/spec/integration/shell/group/group_1.stdout +0 -32
  299. data/spec/integration/shell/help/help_1.cmd +0 -1
  300. data/spec/integration/shell/help/help_1.stdout +0 -24
  301. data/spec/integration/shell/intersect/intersect_0.cmd +0 -1
  302. data/spec/integration/shell/intersect/intersect_0.stdout +0 -9
  303. data/spec/integration/shell/join/join_0.cmd +0 -1
  304. data/spec/integration/shell/join/join_0.stdout +0 -16
  305. data/spec/integration/shell/matching/matching_0.cmd +0 -1
  306. data/spec/integration/shell/matching/matching_0.stdout +0 -8
  307. data/spec/integration/shell/minus/minus_0.cmd +0 -1
  308. data/spec/integration/shell/minus/minus_0.stdout +0 -4
  309. data/spec/integration/shell/not-matching/not-matching_0.cmd +0 -1
  310. data/spec/integration/shell/not-matching/not-matching_0.stdout +0 -5
  311. data/spec/integration/shell/project/project_0.cmd +0 -1
  312. data/spec/integration/shell/project/project_0.stdout +0 -9
  313. data/spec/integration/shell/project/project_1.cmd +0 -1
  314. data/spec/integration/shell/project/project_1.stdout +0 -9
  315. data/spec/integration/shell/quota/quota_0.cmd +0 -1
  316. data/spec/integration/shell/quota/quota_0.stdout +0 -16
  317. data/spec/integration/shell/rank/rank_1.cmd +0 -1
  318. data/spec/integration/shell/rank/rank_1.stdout +0 -10
  319. data/spec/integration/shell/rank/rank_2.cmd +0 -1
  320. data/spec/integration/shell/rank/rank_2.stdout +0 -10
  321. data/spec/integration/shell/rank/rank_3.cmd +0 -1
  322. data/spec/integration/shell/rank/rank_3.stdout +0 -10
  323. data/spec/integration/shell/rank/rank_4.cmd +0 -1
  324. data/spec/integration/shell/rank/rank_4.stdout +0 -6
  325. data/spec/integration/shell/rank/rank_5.cmd +0 -1
  326. data/spec/integration/shell/rank/rank_5.stdout +0 -6
  327. data/spec/integration/shell/rename/rename_0.cmd +0 -1
  328. data/spec/integration/shell/rename/rename_0.stdout +0 -9
  329. data/spec/integration/shell/restrict/restrict_0.cmd +0 -1
  330. data/spec/integration/shell/restrict/restrict_0.stdout +0 -6
  331. data/spec/integration/shell/restrict/restrict_1.cmd +0 -1
  332. data/spec/integration/shell/restrict/restrict_1.stdout +0 -6
  333. data/spec/integration/shell/show/show_base.cmd +0 -1
  334. data/spec/integration/shell/show/show_base.stdout +0 -9
  335. data/spec/integration/shell/show/show_base_sort_1.cmd +0 -1
  336. data/spec/integration/shell/show/show_base_sort_1.stdout +0 -9
  337. data/spec/integration/shell/show/show_base_sort_2.cmd +0 -1
  338. data/spec/integration/shell/show/show_base_sort_2.stdout +0 -9
  339. data/spec/integration/shell/show/show_conflictual.cmd +0 -1
  340. data/spec/integration/shell/show/show_conflictual.stdout +0 -5
  341. data/spec/integration/shell/show/show_csv.cmd +0 -1
  342. data/spec/integration/shell/show/show_csv.stdout +0 -6
  343. data/spec/integration/shell/show/show_ff.cmd +0 -1
  344. data/spec/integration/shell/show/show_ff.stdout +0 -10
  345. data/spec/integration/shell/show/show_rash.cmd +0 -1
  346. data/spec/integration/shell/show/show_rash.stdout +0 -5
  347. data/spec/integration/shell/show/show_rash_pretty.cmd +0 -1
  348. data/spec/integration/shell/show/show_rash_pretty.stdout +0 -30
  349. data/spec/integration/shell/show/show_yaml.cmd +0 -1
  350. data/spec/integration/shell/show/show_yaml.stdout +0 -22
  351. data/spec/integration/shell/sort/sort_0.cmd +0 -1
  352. data/spec/integration/shell/sort/sort_0.stdout +0 -9
  353. data/spec/integration/shell/sort/sort_1.cmd +0 -1
  354. data/spec/integration/shell/sort/sort_1.stdout +0 -9
  355. data/spec/integration/shell/sort/sort_2.cmd +0 -1
  356. data/spec/integration/shell/sort/sort_2.stdout +0 -9
  357. data/spec/integration/shell/sort/sort_3.cmd +0 -1
  358. data/spec/integration/shell/sort/sort_3.stdout +0 -9
  359. data/spec/integration/shell/summarize/summarize_0.cmd +0 -1
  360. data/spec/integration/shell/summarize/summarize_0.stdout +0 -8
  361. data/spec/integration/shell/ungroup/ungroup_0.cmd +0 -1
  362. data/spec/integration/shell/ungroup/ungroup_0.stdout +0 -16
  363. data/spec/integration/shell/union/union_0.cmd +0 -1
  364. data/spec/integration/shell/union/union_0.stdout +0 -9
  365. data/spec/integration/shell/unwrap/unwrap_0.cmd +0 -1
  366. data/spec/integration/shell/unwrap/unwrap_0.stdout +0 -9
  367. data/spec/integration/shell/wrap/wrap_0.cmd +0 -1
  368. data/spec/integration/shell/wrap/wrap_0.stdout +0 -9
  369. data/spec/integration/test_alf.rb +0 -34
  370. data/spec/integration/test_examples.rb +0 -15
  371. data/spec/integration/test_lispy.rb +0 -31
  372. data/spec/integration/test_semantics.rb +0 -40
  373. data/spec/integration/test_shell.rb +0 -47
  374. data/spec/regression/alf_file/__FILE__.alf +0 -2
  375. data/spec/regression/alf_file/suppliers.rash +0 -5
  376. data/spec/regression/alf_file/test___FILE__.rb +0 -17
  377. data/spec/regression/heading/test_heading_with_date.rb +0 -12
  378. data/spec/regression/lispy/test_compile.rb +0 -14
  379. data/spec/regression/logs/apache_combined.log +0 -5
  380. data/spec/regression/logs/test_path_attribute.rb +0 -25
  381. data/spec/regression/relation/test_relation_allbut_all.rb +0 -14
  382. data/spec/regression/relation/test_relation_with_date.rb +0 -12
  383. data/spec/regression/restrict/test_restrict_with_keywords.rb +0 -17
  384. data/spec/shared/a_valid_type_implementation.rb +0 -47
  385. data/spec/shared/a_value.rb +0 -12
  386. data/spec/shared/an_operator_class.rb +0 -36
  387. data/spec/unit/alf-core/aggregator/test_avg.rb +0 -22
  388. data/spec/unit/alf-core/aggregator/test_collect.rb +0 -25
  389. data/spec/unit/alf-core/aggregator/test_concat.rb +0 -31
  390. data/spec/unit/alf-core/aggregator/test_count.rb +0 -17
  391. data/spec/unit/alf-core/aggregator/test_max.rb +0 -23
  392. data/spec/unit/alf-core/aggregator/test_min.rb +0 -23
  393. data/spec/unit/alf-core/aggregator/test_stddev.rb +0 -27
  394. data/spec/unit/alf-core/aggregator/test_sum.rb +0 -23
  395. data/spec/unit/alf-core/aggregator/test_variance.rb +0 -29
  396. data/spec/unit/alf-core/assumptions/test_file.rb +0 -17
  397. data/spec/unit/alf-core/assumptions/test_instance_eval.rb +0 -15
  398. data/spec/unit/alf-core/assumptions/test_scoping.rb +0 -29
  399. data/spec/unit/alf-core/assumptions/test_set.rb +0 -64
  400. data/spec/unit/alf-core/environment/examples/suppliers.rash +0 -5
  401. data/spec/unit/alf-core/environment/test_folder.rb +0 -53
  402. data/spec/unit/alf-core/operator/non_relational/test_autonum.rb +0 -48
  403. data/spec/unit/alf-core/operator/non_relational/test_clip.rb +0 -35
  404. data/spec/unit/alf-core/operator/non_relational/test_coerce.rb +0 -29
  405. data/spec/unit/alf-core/operator/non_relational/test_compact.rb +0 -32
  406. data/spec/unit/alf-core/operator/non_relational/test_defaults.rb +0 -53
  407. data/spec/unit/alf-core/operator/non_relational/test_generator.rb +0 -60
  408. data/spec/unit/alf-core/operator/non_relational/test_sort.rb +0 -60
  409. data/spec/unit/alf-core/operator/relational/test_extend.rb +0 -28
  410. data/spec/unit/alf-core/operator/relational/test_group.rb +0 -39
  411. data/spec/unit/alf-core/operator/relational/test_heading.rb +0 -27
  412. data/spec/unit/alf-core/operator/relational/test_intersect.rb +0 -58
  413. data/spec/unit/alf-core/operator/relational/test_join.rb +0 -36
  414. data/spec/unit/alf-core/operator/relational/test_minus.rb +0 -56
  415. data/spec/unit/alf-core/operator/relational/test_project.rb +0 -62
  416. data/spec/unit/alf-core/operator/relational/test_quota.rb +0 -36
  417. data/spec/unit/alf-core/operator/relational/test_rank.rb +0 -48
  418. data/spec/unit/alf-core/operator/relational/test_rename.rb +0 -26
  419. data/spec/unit/alf-core/operator/relational/test_restrict.rb +0 -45
  420. data/spec/unit/alf-core/operator/relational/test_summarize.rb +0 -44
  421. data/spec/unit/alf-core/operator/relational/test_ungroup.rb +0 -29
  422. data/spec/unit/alf-core/operator/relational/test_union.rb +0 -35
  423. data/spec/unit/alf-core/operator/relational/test_unwrap.rb +0 -26
  424. data/spec/unit/alf-core/operator/relational/test_wrap.rb +0 -26
  425. data/spec/unit/alf-core/operator/signature/test_argv2args.rb +0 -82
  426. data/spec/unit/alf-core/operator/signature/test_collect_on.rb +0 -38
  427. data/spec/unit/alf-core/operator/signature/test_initialize.rb +0 -17
  428. data/spec/unit/alf-core/operator/signature/test_install.rb +0 -56
  429. data/spec/unit/alf-core/operator/signature/test_option_parser.rb +0 -36
  430. data/spec/unit/alf-core/operator/signature/test_parse_args.rb +0 -90
  431. data/spec/unit/alf-core/operator/signature/test_to_lispy.rb +0 -102
  432. data/spec/unit/alf-core/operator/signature/test_to_shell.rb +0 -103
  433. data/spec/unit/alf-core/operator/test_non_relational.rb +0 -20
  434. data/spec/unit/alf-core/operator/test_relational.rb +0 -31
  435. data/spec/unit/alf-core/reader/input.rb +0 -2
  436. data/spec/unit/alf-core/reader/test_alf_file.rb +0 -30
  437. data/spec/unit/alf-core/reader/test_initialize.rb +0 -60
  438. data/spec/unit/alf-core/reader/test_looks_a_path.rb +0 -20
  439. data/spec/unit/alf-core/reader/test_rash.rb +0 -31
  440. data/spec/unit/alf-core/relation/test_coerce.rb +0 -53
  441. data/spec/unit/alf-core/relation/test_inspect.rb +0 -20
  442. data/spec/unit/alf-core/relation/test_relops.rb +0 -55
  443. data/spec/unit/alf-core/relation/test_to_a.rb +0 -41
  444. data/spec/unit/alf-core/renderer/test_initialize.rb +0 -60
  445. data/spec/unit/alf-core/test_aggregator.rb +0 -58
  446. data/spec/unit/alf-core/test_environment.rb +0 -30
  447. data/spec/unit/alf-core/test_operator.rb +0 -16
  448. data/spec/unit/alf-core/test_reader.rb +0 -40
  449. data/spec/unit/alf-core/test_relation.rb +0 -75
  450. data/spec/unit/alf-core/test_renderer.rb +0 -53
  451. data/spec/unit/alf-core/text/test_cell.rb +0 -35
  452. data/spec/unit/alf-core/text/test_row.rb +0 -30
  453. data/spec/unit/alf-core/text/test_table.rb +0 -39
  454. data/spec/unit/alf-core/tools/test_class_name.rb +0 -16
  455. data/spec/unit/alf-core/tools/test_coalesce.rb +0 -19
  456. data/spec/unit/alf-core/tools/test_coerce.rb +0 -16
  457. data/spec/unit/alf-core/tools/test_ruby_case.rb +0 -16
  458. data/spec/unit/alf-core/tools/test_to_lispy.rb +0 -145
  459. data/spec/unit/alf-core/tools/test_to_relation.rb +0 -39
  460. data/spec/unit/alf-core/tools/test_to_ruby_literal.rb +0 -10
  461. data/spec/unit/alf-core/tools/test_tuple_handle.rb +0 -52
  462. data/spec/unit/alf-core/tools/test_tuple_heading.rb +0 -15
  463. data/spec/unit/alf-core/tools/test_varargs.rb +0 -19
  464. data/spec/unit/alf-core/types/test_attr_list.rb +0 -188
  465. data/spec/unit/alf-core/types/test_attr_name.rb +0 -78
  466. data/spec/unit/alf-core/types/test_boolean.rb +0 -42
  467. data/spec/unit/alf-core/types/test_class_methods.rb +0 -24
  468. data/spec/unit/alf-core/types/test_heading.rb +0 -146
  469. data/spec/unit/alf-core/types/test_ordering.rb +0 -185
  470. data/spec/unit/alf-core/types/test_renaming.rb +0 -72
  471. data/spec/unit/alf-core/types/test_size.rb +0 -74
  472. data/spec/unit/alf-core/types/test_summarization.rb +0 -95
  473. data/spec/unit/alf-core/types/test_tuple_computation.rb +0 -96
  474. data/spec/unit/alf-core/types/test_tuple_expression.rb +0 -122
  475. data/spec/unit/alf-core/types/test_tuple_predicate.rb +0 -108
  476. data/spec/unit/alf-csv/input.csv +0 -3
  477. data/spec/unit/alf-csv/test_reader.rb +0 -66
  478. data/spec/unit/alf-csv/test_renderer.rb +0 -73
  479. data/spec/unit/alf-engine/compact/test_set.rb +0 -33
  480. data/spec/unit/alf-engine/compact/test_uniq.rb +0 -33
  481. data/spec/unit/alf-engine/group/test_hash.rb +0 -34
  482. data/spec/unit/alf-engine/join/test_hash.rb +0 -55
  483. data/spec/unit/alf-engine/materialize/test_array.rb +0 -28
  484. data/spec/unit/alf-engine/materialize/test_hash.rb +0 -76
  485. data/spec/unit/alf-engine/quota/test_cesure.rb +0 -34
  486. data/spec/unit/alf-engine/rank/test_cesure.rb +0 -47
  487. data/spec/unit/alf-engine/semi/test_hash.rb +0 -58
  488. data/spec/unit/alf-engine/sort/test_in_memory.rb +0 -32
  489. data/spec/unit/alf-engine/summarize/test_cesure.rb +0 -36
  490. data/spec/unit/alf-engine/summarize/test_hash.rb +0 -36
  491. data/spec/unit/alf-engine/test_aggregate.rb +0 -26
  492. data/spec/unit/alf-engine/test_autonum.rb +0 -24
  493. data/spec/unit/alf-engine/test_clip.rb +0 -34
  494. data/spec/unit/alf-engine/test_coerce.rb +0 -35
  495. data/spec/unit/alf-engine/test_compact.rb +0 -33
  496. data/spec/unit/alf-engine/test_concat.rb +0 -38
  497. data/spec/unit/alf-engine/test_defaults.rb +0 -37
  498. data/spec/unit/alf-engine/test_filter.rb +0 -23
  499. data/spec/unit/alf-engine/test_generator.rb +0 -25
  500. data/spec/unit/alf-engine/test_rename.rb +0 -24
  501. data/spec/unit/alf-engine/test_set_attr.rb +0 -38
  502. data/spec/unit/alf-engine/test_sort.rb +0 -32
  503. data/spec/unit/alf-engine/test_ungroup.rb +0 -28
  504. data/spec/unit/alf-engine/test_unwrap.rb +0 -20
  505. data/spec/unit/alf-engine/test_wrap.rb +0 -26
  506. data/spec/unit/alf-logs/apache_combined.log +0 -5
  507. data/spec/unit/alf-logs/postgresql.log +0 -29
  508. data/spec/unit/alf-logs/test_reader.rb +0 -57
  509. data/spec/unit/alf-sequel/alf.db +0 -0
  510. data/spec/unit/alf-sequel/test_environment.rb +0 -74
  511. data/spec/unit/alf-shell/doc_manager/dynamic.md +0 -1
  512. data/spec/unit/alf-shell/doc_manager/example.md +0 -1
  513. data/spec/unit/alf-shell/doc_manager/example_1.txt +0 -11
  514. data/spec/unit/alf-shell/doc_manager/static.md +0 -1
  515. data/spec/unit/alf-shell/doc_manager/test_call.rb +0 -48
  516. data/spec/unit/alf-shell/main/test_class_methods.rb +0 -44
  517. data/spec/unit/alf-shell/operator/test_autonum.rb +0 -28
  518. data/spec/unit/alf-shell/operator/test_clip.rb +0 -29
  519. data/spec/unit/alf-shell/operator/test_coerce.rb +0 -21
  520. data/spec/unit/alf-shell/operator/test_compact.rb +0 -16
  521. data/spec/unit/alf-shell/operator/test_defaults.rb +0 -29
  522. data/spec/unit/alf-shell/operator/test_extend.rb +0 -21
  523. data/spec/unit/alf-shell/operator/test_generator.rb +0 -37
  524. data/spec/unit/alf-shell/operator/test_group.rb +0 -32
  525. data/spec/unit/alf-shell/operator/test_heading.rb +0 -16
  526. data/spec/unit/alf-shell/operator/test_intersect.rb +0 -18
  527. data/spec/unit/alf-shell/operator/test_join.rb +0 -18
  528. data/spec/unit/alf-shell/operator/test_matching.rb +0 -18
  529. data/spec/unit/alf-shell/operator/test_minus.rb +0 -18
  530. data/spec/unit/alf-shell/operator/test_not_matching.rb +0 -18
  531. data/spec/unit/alf-shell/operator/test_project.rb +0 -38
  532. data/spec/unit/alf-shell/operator/test_quota.rb +0 -23
  533. data/spec/unit/alf-shell/operator/test_rank.rb +0 -30
  534. data/spec/unit/alf-shell/operator/test_rename.rb +0 -21
  535. data/spec/unit/alf-shell/operator/test_restrict.rb +0 -35
  536. data/spec/unit/alf-shell/operator/test_sort.rb +0 -49
  537. data/spec/unit/alf-shell/operator/test_summarize.rb +0 -30
  538. data/spec/unit/alf-shell/operator/test_ungroup.rb +0 -28
  539. data/spec/unit/alf-shell/operator/test_union.rb +0 -18
  540. data/spec/unit/alf-shell/operator/test_unwrap.rb +0 -28
  541. data/spec/unit/alf-shell/operator/test_wrap.rb +0 -30
  542. data/tasks/clean.rake +0 -3
  543. data/tasks/debug_mail.rake +0 -75
  544. data/tasks/debug_mail.txt +0 -18
  545. data/tasks/gh-pages.rake +0 -68
  546. data/tasks/integration_test.rake +0 -43
  547. data/tasks/regression_test.rake +0 -44
  548. data/tasks/unit_test.rake +0 -44
  549. data/tasks/yard.rake +0 -51
@@ -1,45 +1,46 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- backports (2.6.1)
5
- bluecloth (2.2.0)
6
- diff-lcs (1.1.3)
7
- fastercsv (1.5.4)
8
- highline (1.6.11)
9
- myrrha (1.2.2)
4
+ alf-core (0.13.0)
5
+ domain (~> 1.0)
6
+ myrrha (~> 3.0)
7
+ path (~> 1.3)
8
+ sexpr (~> 0.5.1)
9
+ alf-sequel (0.13.0)
10
+ alf-core (~> 0.13.0)
11
+ sequel (~> 3.48)
12
+ alf-shell (0.13.1)
13
+ alf-core (~> 0.13.0)
14
+ quickl (~> 0.4.3)
15
+ diff-lcs (1.2.4)
16
+ domain (1.0.0)
17
+ myrrha (3.0.0)
18
+ domain (~> 1.0)
19
+ path (1.3.1)
20
+ pg (0.14.1)
10
21
  quickl (0.4.3)
11
- rake (0.9.2.2)
12
- redcarpet (2.1.0)
13
- request-log-analyzer (1.11.1)
14
- rspec (2.8.0)
15
- rspec-core (~> 2.8.0)
16
- rspec-expectations (~> 2.8.0)
17
- rspec-mocks (~> 2.8.0)
18
- rspec-core (2.8.0)
19
- rspec-expectations (2.8.0)
20
- diff-lcs (~> 1.1.2)
21
- rspec-mocks (2.8.0)
22
- sequel (3.33.0)
23
- sqlite3 (1.3.5)
24
- wlang (0.10.2)
25
- yard (0.7.5)
22
+ rake (10.1.0)
23
+ rspec (2.14.1)
24
+ rspec-core (~> 2.14.0)
25
+ rspec-expectations (~> 2.14.0)
26
+ rspec-mocks (~> 2.14.0)
27
+ rspec-core (2.14.4)
28
+ rspec-expectations (2.14.0)
29
+ diff-lcs (>= 1.1.3, < 2.0)
30
+ rspec-mocks (2.14.1)
31
+ sequel (3.48.0)
32
+ sexpr (0.5.1)
33
+ sqlite3 (1.3.7)
26
34
 
27
35
  PLATFORMS
28
36
  ruby
29
37
 
30
38
  DEPENDENCIES
31
- backports (~> 2.6)
32
- bluecloth (~> 2.2.0)
33
- fastercsv (~> 1.5.4)
34
- highline (~> 1.6.2)
39
+ alf-core (~> 0.13.0)
40
+ alf-sequel (~> 0.13.0)
41
+ alf-shell (~> 0.13.1)
35
42
  jdbc-sqlite3 (~> 3.7)
36
- myrrha (~> 1.2.1)
37
- quickl (~> 0.4.2)
38
- rake (~> 0.9.2)
39
- redcarpet (~> 2.1.0)
40
- request-log-analyzer (~> 1.11.0)
41
- rspec (~> 2.8.0)
42
- sequel (~> 3.30)
43
+ pg (~> 0.14)
44
+ rake (~> 10.1)
45
+ rspec (~> 2.14)
43
46
  sqlite3 (~> 1.3)
44
- wlang (~> 0.10.2)
45
- yard (~> 0.7.2)
data/LICENCE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # The MIT Licence
2
2
 
3
- Copyright (c) 2011 - Bernard Lambeau & The University of Louvain (Belgium)
3
+ Copyright (c) 2013 - Bernard Lambeau
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -1,17 +1,15 @@
1
- bin/**/*
2
- doc/commands/**/*
3
- doc/operators/**/*
4
- examples/**/*
5
- lib/**/*
6
- spec/**/*
7
- tasks/**/*
8
- Rakefile
9
1
  alf.gemspec
10
2
  alf.noespec
3
+ .gemtest
11
4
  CHANGELOG.md
12
5
  Gemfile
13
6
  Gemfile.lock
7
+ bin/**/*
8
+ lib/**/*
14
9
  LICENCE.md
15
10
  Manifest.txt
11
+ Rakefile
16
12
  README.md
17
- TODO.md
13
+ spec/**/*
14
+ tasks/**/*
15
+ test/**/*
data/README.md CHANGED
@@ -1,567 +1,27 @@
1
- # Alf - Relational Algebra at your fingertips (version 0.10.0)
1
+ # Alf
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/blambeau/alf.png)](http://travis-ci.org/blambeau/alf)
4
- [![Dependency Status](https://gemnasium.com/blambeau/alf.png)](https://gemnasium.com/blambeau/alf)
3
+ Relational Algebra at your fingertips
5
4
 
6
- ## Description
5
+ [![Build Status](https://secure.travis-ci.org/alf-tool/alf.png)](http://travis-ci.org/alf-tool/alf)
6
+ [![Dependency Status](https://gemnasium.com/alf-tool/alf.png)](https://gemnasium.com/alf-tool/alf)
7
7
 
8
- ### What & Why
8
+ ## Links
9
9
 
10
- Alf brings the relational algebra both in Shell and in Ruby. In Shell, because
11
- manipulating any relation-like data source should be as straightforward as a
12
- one-liner. In Ruby, because I've never understood why programming languages
13
- provide data structures like arrays, hashes, sets, trees and graphs but not
14
- _relations_... Let's stop the segregation ;-)
10
+ * [Official documentation](http://blambeau.github.com/alf)
11
+ * [Source and Issues](http://github.com/alf-tool/alf)
12
+ * [Relational basics as needed](http://www.revision-zero.org/relational-basics-2)
15
13
 
16
- ### Install
14
+ ## What & Why
17
15
 
18
- % [sudo] gem install alf [fastercsv, ...]
19
- % alf --help
20
-
21
- ### Bundler & Require
22
-
23
- # API is not considered stable enough for now, please use
24
- gem "alf", "= 0.10.0"
25
-
26
- # The following should not break your code, but is a bit less safe,
27
- # until 1.0.0 has been reached
28
- gem "alf", "~> 0.10.0"
29
-
30
- ### Links
31
-
32
- * http://blambeau.github.com/alf
33
- * http://rubydoc.info/gems/alf
34
- * http://github.com/blambeau/alf
35
- * http://rubygems.org/gems/alf
36
-
37
- ### Quick overview
38
-
39
- Alf is a commandline tool and Ruby library to manipulate data with all the power
40
- of a truly relational algebra approach. Objectives behind Alf are manifold:
41
-
42
- * Pragmatically, Alf aims at being a useful commandline executable for manipulating
43
- relational-like data: database records, csv files, or **whatever can be interpreted
44
- as (the physical encoding of) a relation**. See 'alf --help' for the list of
45
- available commands and implemented relational operators.
46
-
47
- % alf restrict suppliers -- "city == 'London'" | alf join cities
48
-
49
- * Alf is also a 100% Ruby relational algebra implementation shipped with a simple
50
- to use, powerful, functional DSL for compiling and evaluating relational queries.
51
- Alf is not limited to simple scalar values, but admits values of arbitrary
52
- complexity (under a few requirements about their implementation, see next
53
- section). See 'alf --help' as well as .alf files in the examples directory
54
- for syntactic examples.
55
-
56
- Alf.lispy.evaluate {
57
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
58
- }
59
-
60
- In addition to this functional syntax, Alf comes bundled with an in-memory
61
- Relation data structure that provides an object-oriented way of manipulating
62
- relations in simplest cases:
63
-
64
- suppliers = Alf::Relation[
65
- {:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'},
66
- {:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'},
67
- {:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'},
68
- {:sid => 'S4', :name => 'Clark', :status => 20, :city => 'London'},
69
- {:sid => 'S5', :name => 'Adams', :status => 30, :city => 'Athens'},
70
- ]
71
- cities = ...
72
- puts suppliers.restrict(lambda{ city == 'London' }).join(cities)
73
-
74
- * Alf is also an educational tool, that I've written to draw people attention
75
- about the ill-known relational theory (and ill-represented by SQL). The tool
76
- is largely inspired from **Tutorial D**, the tutorial language of Chris Date and
77
- Hugh Darwen in their books, more specifically in
78
- {http://www.thethirdmanifesto.com/ *The Third Manifesto* (TTM)}.
79
- However, Alf only provides an overview of the relational _algebra_ defined
80
- there (Alf is neither a relational _database_, nor a relational _language_).
81
- I hope that people (especially talented developers) will be sufficiently
82
- enticed by features shown here to open that book, read it more deeply, and
83
- implement new stuff around Date & Darwen's vision. Have a look at the result of
84
- the following query for the kind of things that you'll never ever have in SQL
85
- (see also 'alf help quota', 'alf help wrap', 'alf help group', ...):
86
-
87
- % alf --text summarize supplies -- sid -- total "sum{ qty }" which "collect{ pid }"
88
-
89
- * Last, but not least, Alf is an attempt to help me test some research ideas and
90
- communicate about them with people that already know (all or part) of the TTM
91
- vision of relational theory. These people include members of the TTM mailing
92
- list as well as other people implementing some of the TTM ideas (see
93
- {https://github.com/dkubb/veritas Dan Kubb's Veritas project} for example). For
94
- this reason, specific features and/or operators are mine, should be considered
95
- 'research work in progress', and used with care because not necessarily in
96
- conformance with the TTM.
97
-
98
- % alf --text quota supplies -- sid -- qty -- pos "count()"
99
-
100
- ## Overview of relational theory
101
-
102
- We quickly recall relational theory in this section, as described in the TTM
103
- book. Readers not familiar with Date and Darwen's vision of relational theory
104
- should probably read this section, even if fluent in SQL. Others may probably
105
- skip this section. A quick test?
106
-
107
- > _A relation is a value, precisely a set of tuples, which are themselves values.
108
- Therefore, a relation is immutable, not ordered, does not contain duplicates,
109
- and does not have null/nil attributes._
110
-
111
- Familiar? Skip. Otherwise, read on.
112
-
113
- ### The example database
114
-
115
- This README file shows a lot of examples built on top of the following suppliers
116
- & parts database (almost identical to the original version in C. J. Date's database
117
- books). By default, the alf command line is wired to this embedded example. All
118
- examples shown here should therefore work immediately, if you want to reproduce
119
- them!
120
-
121
- % alf show database
122
-
123
- +-------------------------------------+-------------------------------------------------+-------------------------+------------------------+
124
- | :suppliers | :parts | :cities | :supplies |
125
- +-------------------------------------+-------------------------------------------------+-------------------------+------------------------+
126
- | +------+-------+---------+--------+ | +------+-------+--------+------------+--------+ | +----------+----------+ | +------+------+------+ |
127
- | | :sid | :name | :status | :city | | | :pid | :name | :color | :weight | :city | | | :city | :country | | | :sid | :pid | :qty | |
128
- | +------+-------+---------+--------+ | +------+-------+--------+------------+--------+ | +----------+----------+ | +------+------+------+ |
129
- | | S1 | Smith | 20 | London | | | P1 | Nut | Red | 12.0000000 | London | | | London | England | | | S1 | P1 | 300 | |
130
- | | S2 | Jones | 10 | Paris | | | P2 | Bolt | Green | 17.0000000 | Paris | | | Paris | France | | | S1 | P2 | 200 | |
131
- | | S3 | Blake | 30 | Paris | | | P3 | Screw | Blue | 17.0000000 | Oslo | | | Athens | Greece | | | S1 | P3 | 400 | |
132
- | | S4 | Clark | 20 | London | | | P4 | Screw | Red | 14.0000000 | London | | | Brussels | Belgium | | | S1 | P4 | 200 | |
133
- | | S5 | Adams | 30 | Athens | | | P5 | Cam | Blue | 12.0000000 | Paris | | +----------+----------+ | | S1 | P5 | 100 | |
134
- | +------+-------+---------+--------+ | | P6 | Cog | Red | 19.0000000 | London | | | | S1 | P6 | 100 | |
135
- | | +------+-------+--------+------------+--------+ | | | S2 | P1 | 300 | |
136
- | | | | | S2 | P2 | 400 | |
137
- | | | | | S3 | P2 | 200 | |
138
- | | | | | S4 | P2 | 200 | |
139
- | | | | | S4 | P4 | 300 | |
140
- | | | | | S4 | P5 | 400 | |
141
- | | | | +------+------+------+ |
142
- +-------------------------------------+-------------------------------------------------+-------------------------+------------------------+
143
-
144
- Many people think that relational databases are necessary 'flat', that they are
145
- necessarily limited to simple scalar values put in two dimension tables. This is
146
- wrong; most SQL databases are indeed 'flat', but _relations_ (in the mathematical
147
- sense of the relational theory) are not! Look, **the example above is a relation!**;
148
- that 'contains' other relations as particular values, which, in turn, could
149
- 'contain' relations or any other 'simple' or more 'complex' value... This is not
150
- "flat" at all, after all :-)
151
-
152
- ### Types and Values
153
-
154
- To understand what is a relation exactly, one needs to remember elementary
155
- notions of set theory and the concepts of _type_ and _value_.
156
-
157
- * A _type_ is a finite set of values; it is not particularly ordered and, being
158
- a set, it does never contain two values which are equal (any type is necessarily
159
- accompanied with an equality operator, denoted here by '==').
160
-
161
- * A _value_ is **immutable** (you cannot 'change' a value, in any way), has no
162
- localization in time and space, and is always typed (that is, it is always
163
- accompanied by some identification of the type it belongs to).
164
-
165
- As you can see, _type_ and _value_ are not the same concepts as _class_ and
166
- _object_, which you are probably more familiar with. Alf considers that the
167
- latter are _implementations_ of the former. Alf assumes _valid_ implementations
168
- (equality and hash methods must be correct) and _valid_ usage (objects used for
169
- representing values are kept immutable in practice). Alf _assumes_ this, but
170
- does not _enforces_ it: it is your responsibility to use Alf in conformance with
171
- these preconditions. That being said, if you want **arrays, colors, ranges, or
172
- whatever in your relations**, just do it! You can even join on them, restrict on
173
- them, summarize on them, and so on:
174
-
175
- % alf extend suppliers -- chars "name.chars.to_a" | alf --text restrict -- "chars.last == 's'"
176
-
177
- +------+-------+---------+--------+-----------------+
178
- | :sid | :name | :status | :city | :chars |
179
- +------+-------+---------+--------+-----------------+
180
- | S2 | Jones | 10 | Paris | [J, o, n, e, s] |
181
- | S5 | Adams | 30 | Athens | [A, d, a, m, s] |
182
- +------+-------+---------+--------+-----------------+
183
-
184
- A last, very important word about values. **Null/nil is not a value**. Strictly
185
- speaking therefore, you may not use null/nil inside your data files or datasources
186
- representing relations. That being said, Alf provides specific support for handling
187
- them, because they appear in today's databases in practice and that Alf aims at
188
- being a tool that helps you tackling _practical_ problems. See the section with
189
- title "Why is Alf Exactly?" later.
190
-
191
- ### Tuples and Relations
192
-
193
- Tuples (aka records) and relations are values as well, which explains why you
194
- can have them inside relations!
195
-
196
- * Logically speaking, a tuple is a set of (attribute name, attribute value)
197
- pairs. Moreover, it does not contain two attributes with the same name and is
198
- **not particularly ordered**. Also, **a tuple is a _value_, and is therefore
199
- immutable**. Last, but not least, a tuple **does not admit nulls/nils**. Tuples
200
- in Alf are simply implemented with ruby hashes, taken as tuple implementations.
201
- Not all hashes are valid tuple implementations, of course (those containing nil
202
- are not, for example). Alf _assumes_ valid tuples, but does not _enforce_ this
203
- precondition. It's up to you to use Alf the right way! No support is or will
204
- ever be provided for ordering tuple attributes. However, as hashes are ordered
205
- in Ruby 1.9, Alf implements a best effort strategy to keep a friendly ordering
206
- when rendering tuples and relations. This is a very good practical reason for
207
- migrating to ruby 1.9 if not already done!
208
-
209
- {:sid => "S1", :name => "Smith", :status => 20, :city => "London"}
210
-
211
- * A _relation_ is a set of tuples. Being a set, a relation does **never contain
212
- duplicates** (unlike SQL that works on bags, not on sets) and is **not
213
- particularly ordered**. Moreover, all tuples of a relation must have the same
214
- _heading_, that is, the same set of attribute (name, type) pairs. Also, **a
215
- relation is a _value_, is therefore immutable** and **does not admit null/nil**.
216
-
217
- Alf is mainly an implementation of relational algebra (see section below). The
218
- implemented operators consider any Iterator of tuples as potentially valid
219
- operand. In addition Alf provides a Relation ruby class, that acts as an
220
- in-memory data structure that provides an Object-Oriented API to call operators
221
- (see "Interfacing Alf in Ruby" below).
222
-
223
- ### Relational Algebra
224
-
225
- In classical algebra, you can make computations like <code>(5 + 2) - 3</code>.
226
- In relational algebra, you can make similar things on relations. Alf uses an
227
- infix, functional programming-oriented syntax for algebra expressions:
228
-
229
- (minus (union :suppliers, xxx), yyy)
230
-
231
- All relational operators take relation operands in input and return a relation
232
- as output. We say that the relational algebra is _closed_ under its operators.
233
- In practice, it means that operands may always be sub-expressions, **always**.
234
-
235
- (minus (union (restrict :suppliers, lambda{ zzz }), xxx), yyy)
236
-
237
- In shell, the closure property means that you can pipe alf invocations the way
238
- you want! The same query, in shell:
239
-
240
- alf restrict suppliers -- "zzz" | alf union xxx | alf minus yyy
241
-
242
- ## What is Alf exactly?
243
-
244
- *The Third Manifesto* defines a series of prescriptions, proscriptions and very
245
- strong suggestions for designing a truly relational _language_, called a _D_,
246
- as an alternative to SQL for managing relational databases. This is far behind
247
- my objective with Alf, as it does not touch at database issues at all (persistence,
248
- transactions, and so on.) and don't actually define a programming language (only
249
- a small functional ruby DSL).
250
-
251
- Alf must simply be interpreted as a ruby library implementing (a variant of)
252
- Date and Darwen's relational algebra. This library is designed as a set of operator
253
- implementations, that work as tuple iterators taking other tuple iterators as
254
- input. Under the pre-condition that you provide them _valid_ tuple iterators as
255
- input (no duplicates, no nil, + other preconditions on an operator basis), the
256
- result is a valid iterator as well. Unless explicitely stated otherwise, any
257
- behavior observed when not respecting these preconditions, even an interesting
258
- behavior, is not guaranteed and might change with tiny version changes (see
259
- section about versioning policy at the end of this file).
260
-
261
- ### The command line utility
262
-
263
- #
264
- # Provided that suppliers and cities are valid relation representations
265
- # [something similar]
266
- #
267
- % alf restrict suppliers -- "city == 'London'" | alf join cities
268
-
269
- # the resulting stream is a valid relation representation in the output
270
- # stream format that you have selected (.rash by default). It can therefore
271
- # be piped to another alf shell invocation, or saved to a file and re-read
272
- # later (under the assumption that input and output data formats match, or
273
- # course). [Something similar about responsibility and bug].
274
-
275
- If you take a look at .alf example files, you'll find functional ruby expressions
276
- like the following (called Lispy expressions):
277
-
278
- % cat examples/operators/minus.alf
279
-
280
- # Give all suppliers, except those living in Paris
281
- (minus :suppliers,
282
- (restrict :suppliers, lambda{ city == 'Paris' }))
283
-
284
- # This is a contrived example for illustrating minus, as the
285
- # following is equivalent
286
- (restrict :suppliers, lambda{ city != 'Paris' })
287
-
288
- You can simply execute such expressions with the alf command line itself (the
289
- three following invocations return the same result):
290
-
291
- % alf examples/operators/minus.alf | alf show
292
- % alf show minus
293
- % alf -e "(restrict :suppliers, lambda{ city != 'Paris' })" | alf show
294
-
295
- Symbols are magically resolved from the environment, which is wired to the
296
- examples by default. See the dedicated sections below to update this behavior
297
- to your needs.
298
-
299
- ### The algebra compiler
300
-
301
- #
302
- # Provided that :suppliers and :cities are valid relation representations
303
- # (under the responsibility shared by you and the Reader and Environment
304
- # subclasses you use -- see later), then,
305
- #
306
- op = Alf.lispy.compile {
307
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
308
- }
309
-
310
- # op is a thread-safe Enumerable of tuples, that can be taken as a valid
311
- # relation representation. It can therefore be used as the input operand
312
- # of any other expression. This is under Alf's responsibility, and any
313
- # failure must be considered a bug!
314
-
315
- ### The Relation data structure
316
-
317
- In addition, Alf is bundled with an in-memory Relation data structure that
318
- provided a more abstract API for manipulating relations in simple cases (the
319
- rules are the same about pre and post-conditions):
320
-
321
- # The query above can be done as follows. Note that relations are always
322
- # loaded in memory here!
323
- suppliers = Alf::Relation[ ... ]
324
- cities = Alf::Relation[ ... ]
325
- suppliers.restrict(lambda{ city == 'London' }).
326
- join(cities)
327
- # => Alf::Relation[ ... ]
328
-
329
- All relational operators have an instance method equivalent on the Alf::Relation
330
- class. Semantically, the receiver object is simply the first operand of the
331
- functional call, as illustrated above.
332
-
333
- ### Where do relations come from?
334
-
335
- Relation literals can simply be written as follows:
336
-
337
- suppliers = Alf::Relation[
338
- {:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'},
339
- {:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'},
340
- {:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'},
341
- {:sid => 'S4', :name => 'Clark', :status => 20, :city => 'London'},
342
- {:sid => 'S5', :name => 'Adams', :status => 30, :city => 'Athens'},
343
- ]
344
-
345
- Environment classes serve datasets (see later) that always have a to_rel method
346
- for obtaining in-memory relations:
347
-
348
- env = Alf::Environment.examples
349
- env.dataset(:suppliers).to_rel
350
- # => Alf::Relation[ ... ]
351
-
352
- Compiled expressions always have a to_rel method that allows obtaining an
353
- in-memory relation:
354
-
355
- op = Alf.lispy.compile {
356
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
357
- }
358
- op.to_rel
359
- # => Alf::Relation[...]
360
-
361
- Lispy provides an 'evaluate' method which is precisely equivalent to the chain
362
- above. Therefore:
363
-
364
- rel = Alf.lispy.evaluate {
365
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
366
- }
367
- # => Alf::Relation[...]
368
-
369
- ### Algebra is closed under its operators!
370
-
371
- Of course, from the closure property of a relational algebra (that states that
372
- operators works on relations and return relations), you can use a sub expression
373
- *everytime* a relational operand is expected, everytime:
374
-
375
- # Compute the total qty supplied in each country together with the subset
376
- # of products shipped there. Only consider suppliers that have a status
377
- # greater than 10, however.
378
- (summarize \
379
- (join \
380
- (join (restrict :suppliers, lambda{ status > 10 }),
381
- :supplies),
382
- :cities),
383
- [:country],
384
- :which => Agg::collect(:pid),
385
- :total => Agg::sum{ qty })
386
-
387
- Of course, complex queries quickly become unreadable that way. But you can always
388
- split complex tasks in more simple ones:
389
-
390
- kept_suppliers = (restrict :suppliers, lambda{ status > 10 })
391
- with_countries = (join kept_suppliers, :cities),
392
- supplying = (join with_countries, :supplies)
393
- (summarize supplying,
394
- [:country],
395
- :which => Agg::collect(:pid),
396
- :total => Agg::sum{ qty })
397
-
398
- And here is the result !
399
-
400
- +------+--------+--------------------------+
401
- | :sid | :total | :which |
402
- +------+--------+--------------------------+
403
- | S1 | 1300 | [P1, P2, P3, P4, P5, P6] |
404
- | S2 | 700 | [P1, P2] |
405
- | S3 | 200 | [P2] |
406
- | S4 | 900 | [P2, P4, P5] |
407
- +------+--------+--------------------------+
408
-
409
- ### Reference API
410
-
411
- For now, the Ruby API is documented in the commandline help itself (a cheatsheet
412
- or something will be provided as soon as possible). For example, you'll find the
413
- allowed syntaxes for RESTRICT as follows:
414
-
415
- % alf help restrict
416
-
417
- ...
418
- API & EXAMPLE
419
-
420
- # Restrict to suppliers with status greater than 20
421
- (restrict :suppliers, lambda{ status > 20 })
422
-
423
- # Restrict to suppliers that live in London
424
- (restrict :suppliers, lambda{ city == 'London' })
425
- ...
426
-
427
- ### Coping with non-relational data sources (nil, duplicates, etc.)
428
-
429
- Alf aims at being a tool that helps you tackling practical problems, and
430
- denormalized and/or noisy data is one of them. Missing values occur. Duplicates
431
- abound in SQL databases lacking primary keys, and so on. Using Alf's relational
432
- operators on such inputs is not a good idea, because it is a strong precondition
433
- violation. This is not because relational theory is weak, but because extending
434
- it to handle null/nil and duplicates correctly has been proven at best a nightmare,
435
- and at worse a mess. As a practical exercice, try to extend classical algebra
436
- with versions of +, - * and / that handle nil in such a way that the resulting
437
- theory is sound and still looks intuitive! Then do it on boolean algebra with
438
- _and_, _or_ and _not_. Then, add null/nil to classical set theory. Classical
439
- algebra, boolean algebra, and set theory are important building blocks behind
440
- relational algebra because almost all of its operators are defined on top of
441
- them...
442
-
443
- So what? The approach choosen in Alf to handle this conflict is very pragmatic.
444
- First of all, Alf implements a best effort strategy -- where possible -- to
445
- remain friendly in presence of null/nil on attributes that have no influence on
446
- an operator's job. For example, the query below will certainly fail if _status_
447
- is null/nil, but it won't probably fail if any other attribute is nil.
448
-
449
- % alf restrict suppliers -- "status > 10"
450
-
451
- This best-effort strategy is not enough, and striclty speaking, must be considered
452
- unsound (for example, it strongly hurts optimization possibilities). Therefore,
453
- I strongly encourage you to go a step further: **if relational operators want
454
- true relations as input, please, give them!**. For this, Alf also provides a few
455
- non-relational operators in addition to relational ones. Those operators must be
456
- interpreted as "pre-relational" operators, in the sense that they help obtaining
457
- valid relation representations from invalid ones. Provided that you use them
458
- correctly, their output can safely be used as input of a relational operator.
459
- You'll find,
460
-
461
- * <code>alf autonum</code> -- ensure no duplicates by generating a unique attribute
462
- * <code>alf compact</code> -- brute-force duplicates removal
463
- * <code>alf defaults</code> -- replace nulls/nil by valid values, on an attribute basis
464
-
465
- Play the game, it's easy!
466
-
467
- - _Give id, name and status of suppliers whose status is greater that 10_
468
- - Hey man, we don't know the status for all suppliers! What about these cases?
469
- - _Ignore them_
470
- - No problem dude!
471
-
472
- % alf defaults --strict suppliers -- sid '' name '' status 0 | alf restrict -- "status > 10"
473
-
474
- ### Alf is duck-typed
475
-
476
- The relational theory is often considered under a statically-typed point
477
- of view. When considering tuples and relations, for example, the notion of
478
- _heading_, a set of (name,type) pairs, is central. For example, a heading for
479
- a supplier tuple/relation could be:
480
-
481
- {:sid => String, :name => Name, :status => Integer, :city => String}
482
-
483
- Most relational operators have preconditions in terms of the headings of their
484
- operands. For example, _minus_ and _union_ require their operands to have same
485
- heading, while _rename_ requires renamed attributes to exist in operand's
486
- heading, and so on. Given an expression in relational algebra, it is always
487
- possible to compute the heading of the resulting relation, by statically
488
- analyzing the whole query expression in the light of a catalog of typed
489
- operators. This way, a tool can check that a query is statically valid, i.e.
490
- that it respects operator preconditions. While this approach has the major
491
- advantage of allowing strong optimizations, it also has a few drawbacks (as
492
- the need to know the heading of used datasources in advance) and is difficult to
493
- mary with dynamically-typed languages like Ruby. Therefore, Alf takes another
494
- approach, which is similar to duck-typing. In essence, this approach can be
495
- summarized as follows:
496
-
497
- - _You have the responsibility of not violating operators' preconditions. If you
498
- do, Alf has the responsibility of returning correct results._.
499
- - No problem dude!
500
-
501
- ## More about the shell command line
502
-
503
- % alf --help
504
-
505
- The help command will display the list of available operators. Each of them is
506
- completely described with 'alf help OPERATOR'. They all have a similar invocation
507
- syntax in shell:
508
-
509
- % alf operator operands... -- args...
510
-
511
- For example, try the following:
512
-
513
- # display suppliers that live in Paris
514
- % alf restrict suppliers -- "city == 'Paris'"
515
-
516
- # join suppliers and cities (no args here)
517
- % alf join suppliers cities
518
-
519
- ### Recognized data streams/files (.rash files)
520
-
521
- For educational purposes, 'suppliers' and 'cities' inputs are magically resolved
522
- as denoting the files examples/operators/suppliers.rash and
523
- examples/operators/cities.rash, respectively. You'll find other data files:
524
- parts.rash, supplies.rash that are resolved magically as well and with which you
525
- can play. For non-educational purposes, operands may always be explicit files,
526
- or you can force the folder in which datasource files have to be found:
527
-
528
- # The following invocations are equivalent
529
- % alf restrict /tmp/foo.rash -- "..."
530
- % alf --env=/tmp restrict foo -- "..."
531
-
532
- A .rash file is simply a file in which each line is a ruby Hash, intended to
533
- represent a tuple. Under theory-driven preconditions, a .rash file can be seen
534
- as a valid (straightforward but useful) physical representation of a relation!
535
- When used in shell, alf dumps query results in the .rash format by default,
536
- which opens the ability of piping invocations! Indeed, unary operators read their
537
- operand on standard input if not specific as command argument. For example, the
538
- invocation below is equivalent to the one given above.
539
-
540
- # display suppliers that live in Paris
541
- % cat examples/operators/suppliers.rash | alf restrict -- "city == 'Paris'"
542
-
543
- Similarly, when only one operand is present in invocations of binary operators,
544
- they read their left operand from standard input. Therefore, the join given in
545
- previous section can also be written as follows:
546
-
547
- % cat examples/operators/suppliers.rash | alf join cities
548
-
549
- The relational algebra is _closed_ under its operators, which means that these
550
- operators take relations as operands and return a relation. Therefore operator
551
- invocations can be nested, that is, operands can be other relational expressions.
552
- When you use alf in a shell, it simply means that you can pipe operators as you
553
- want:
16
+ Alf brings the relational algebra both in Shell and in Ruby. In Shell, because
17
+ manipulating any relation-like data source should be as straightforward as a one-liner.
18
+ In Ruby, because I've never understood why programming languages provide data structures
19
+ like arrays, hashes, sets, trees and graphs but not _relations_...
554
20
 
555
- % alf show --rash suppliers | alf join cities | alf restrict -- "status > 10"
21
+ ## Shell Example
556
22
 
557
- ### Obtaining a friendly output
23
+ % alf --examples show suppliers
558
24
 
559
- The show command (which is **not** a relational operator) can be used to obtain
560
- a more friendly output:
561
-
562
- # it renders a text table by default
563
- % alf show [--text] suppliers
564
-
565
25
  +------+-------+---------+--------+
566
26
  | :sid | :name | :status | :city |
567
27
  +------+-------+---------+--------+
@@ -572,226 +32,112 @@ a more friendly output:
572
32
  | S5 | Adams | 30 | Athens |
573
33
  +------+-------+---------+--------+
574
34
 
575
- # and reads from standard input without argument!
576
- % alf restrict suppliers "city == 'Paris'" | alf show
577
-
578
- +------+-------+---------+-------+
579
- | :sid | :name | :status | :city |
580
- +------+-------+---------+-------+
581
- | S2 | Jones | 10 | Paris |
582
- | S3 | Blake | 30 | Paris |
583
- +------+-------+---------+-------+
584
-
585
- Other formats can be obtained (see 'alf help show'). For example, you can generate
586
- a .yaml file, as follows:
587
-
588
- % alf restrict suppliers -- "city == 'Paris'" | alf show --yaml
589
-
590
- ### Executing .alf files
591
-
592
- You'll also find .alf files in the examples folder, that contain more complex
593
- examples in the Ruby functional syntax (see section below).
594
-
595
- % cat examples/operators/group.alf
596
- #!/usr/bin/env alf
597
- (group :supplies, [:pid, :qty], :supplying)
598
-
599
- You can simply execute these files with alf directly as follows:
600
-
601
- # the following works, as well as the shortcut 'alf show group'
602
- % alf examples/group.alf | alf show
603
-
604
- +------+-----------------+
605
- | :sid | :supplying |
606
- +------+-----------------+
607
- | S1 | +------+------+ |
608
- | | | :pid | :qty | |
609
- | | +------+------+ |
610
- | | | P1 | 300 | |
611
- | | | P2 | 200 | |
612
- ...
613
-
614
- Also, mimicing the ruby executable, the following invocation is also possible:
615
-
616
- % alf -e "(restrict :suppliers, lambda{ city == 'Paris' })"
617
-
618
- where the argument is a relational expression in Alf's Lispy dialect, which
619
- is detailed in the next section.
620
-
621
- ## More about Alf in Ruby
622
-
623
- ### Calling commands 'ala' shell
624
-
625
- For simple cases, the easiest way of using Alf in ruby is probably to mimic
626
- what you have in shell:
627
-
628
- % alf restrict suppliers -- "city == 'Paris'"
629
-
630
- Then, in ruby
631
-
632
- #
633
- # 1. create an engine on an environment (see section about environments later)
634
- # 2. run a command
635
- # 3. op is a thread-safe enumerable of tuples, see the Lispy section below)
636
- #
637
- lispy = Alf.lispy(Alf::Environment.examples)
638
- op = lispy.run(['restrict', 'suppliers', '--', "city == 'Paris'"])
639
-
640
- If this kind of API is not sufficiently expressive for you, you'll have to learn
641
- the APIs deeper, and use the Lispy functional style that Alf provides, which can
642
- be compiled and used as explained in the next section.
643
-
644
- ### Compiler vs. Relation data structure
645
-
646
- The compilers allow you to manipulate algebra expressions. Just obtain a Lispy
647
- instance on an environment and you're ready:
648
-
649
- #
650
- # Expressions can simply be compiled as illustrated below. We use the
651
- # examples environment here, see the dedicated section later about other
652
- # available environments.
653
- #
654
- lispy = Alf.lispy(Alf::Environment.examples)
655
- london_suppliers = lispy.compile do
656
- (restrict :suppliers, lambda{ city == 'London' })
657
- end
658
-
659
- #
660
- # Returned operator is an enumerable of ruby hashes. Provided that datasets
661
- # offered by the environment (:suppliers here) can be enumerated more than
662
- # once, the operator may be used multiple times and is even thread safe!
663
- #
664
- london_suppliers.each do |tuple|
665
- # tuple is a ruby Hash
666
- end
667
-
668
- #
669
- # Now, maybe you want to reuse op in a larger query, for example
670
- # by projecting on the city attribute... Here is how this can be
671
- # done:
672
- #
673
- projection = (project london_suppliers, [:city])
674
-
675
- Note that the examples above manipulate algebra operators, not relations per se.
676
- This means that equality and other such operators, that operate on relation
677
- _values_, do not operate correctly here:
678
-
679
- projection == Alf::Relation[{:city => 'London'}]
680
- # => nil
681
-
682
- In contrast, you can use such operators when operating on true relation values:
683
-
684
- projection.to_rel == Alf::Relation[{:city => 'London'}]
685
- # => true
686
-
687
- ### Using/Implementing other Environments
688
-
689
- An Environment instance if passed as first argument of <code>Alf.lispy</code>
690
- and is responsible of resolving named datasets. A base class Environment::Folder
691
- is provided with the Alf distribution, with a factory method on the Environment
692
- class itself.
693
-
694
- env = Alf::Environment.folder("path/to/a/folder")
695
-
696
- An environment built that way will look for .rash and .alf files in the specified
697
- folder and sub-folders. I'll of course strongly consider any contribution
698
- implementing the Environment contract on top of SQL or NoSQL databases or anything
699
- that can be useful to manipulate with relational algebra. Such contributions can
700
- be added to the project directly. A base template would look like:
701
-
702
- class Foo < Alf::Environment
703
-
704
- #
705
- # You should at least implement the _dataset_ method that resolves a
706
- # name (a Symbol instance) to an Enumerable of tuples (typically a
707
- # Reader). See Alf::Environment for exact contract details.
708
- #
709
- def dataset(name)
710
- end
711
-
712
- end
713
-
714
- Read more about Environment's API so as to let your environment be recognized
715
- in shell (--env=...) on rubydoc.info
716
-
717
- ### Adding file decoders, aka Readers
718
-
719
- Environments should not be confused with Readers (see Reader class and its
720
- subclasses). While the former resolve named datasets, the latter decode files
721
- and/or other resources as tuple enumerables. Environments typically serve Reader
722
- instances in response to dataset resolving.
723
-
724
- Reader implementations decoding .rash and .alf files are provided in the main
725
- alf.rb file. It's relatively easy to implement the Reader contract by extending
726
- the Reader class and implementing an each method. Once again, contributions are
727
- very welcome in lib/alf/reader (.csv files, .log files, and so on). A basic
728
- template for this is as follows:
729
-
730
- class Bar < Alf::Reader
731
-
732
- #
733
- # You should at least implement each, see Alf::Reader which provides a
734
- # base implementation and a few tools
735
- #
736
- def each
737
- # [...]
738
- end
739
-
740
- # By registering it, the Folder environment will automatically
741
- # recognize and decode .bar files correctly!
742
- Alf::Reader.register(:bar, [".bar"], self)
743
-
744
- end
745
-
746
- ### Adding outputters, aka Renderers
747
-
748
- Similarly, you can contribute renderers to output relations in html, or whatever
749
- format you would consider interesting. See the Renderer class, and consider the
750
- following template for contributions in lib/alf/renderer
751
-
752
- class Glim < Alf::Renderer
753
-
754
- #
755
- # You should at least implement the execute method that renders tuples
756
- # given in _input_ (an Enumerable of tuples) on the output buffer
757
- # and returns the latter. See Alf::Renderer for the exact contract
758
- # details.
759
- #
760
- def execute(output = $stdout)
761
- # [...]
762
- output
763
- end
764
-
765
-
766
- # By registering it, the output options of 'alf show' will
767
- # automatically provide your --glim contribution
768
- Alf::Renderer.register(:glim, "as a .glim file", self)
769
-
770
- end
35
+ % alf --examples group suppliers -- size name status -- in_that_city
36
+
37
+ +--------+----------------------------+
38
+ | :city | :in_that_city |
39
+ +--------+----------------------------+
40
+ | London | +------+-------+---------+ |
41
+ | | | :sid | :name | :status | |
42
+ | | +------+-------+---------+ |
43
+ | | | S1 | Smith | 20 | |
44
+ | | | S4 | Clark | 20 | |
45
+ | | +------+-------+---------+ |
46
+ | Paris | +------+-------+---------+ |
47
+ | | | :sid | :name | :status | |
48
+ | | +------+-------+---------+ |
49
+ | | | S2 | Jones | 10 | |
50
+ | | | S3 | Blake | 30 | |
51
+ | | +------+-------+---------+ |
52
+ | Athens | +------+-------+---------+ |
53
+ | | | :sid | :name | :status | |
54
+ | | +------+-------+---------+ |
55
+ | | | S5 | Adams | 30 | |
56
+ | | +------+-------+---------+ |
57
+ +--------+----------------------------+
58
+
59
+ ## Ruby Example
60
+
61
+ # Let get the same database in ruby
62
+ db = Alf.examples
63
+
64
+ # Group suppliers by city
65
+ grouped = db.query{
66
+ group(:suppliers, [:sid, :name, :status], :in_that_city)
67
+ }
68
+ # => same result as in shell
69
+
70
+ # Let make some computations on the sub-relations
71
+ db.query{
72
+ extend(grouped, how_many: ->{ in_that_city.count },
73
+ avg_status: ->{ in_that_city.avg{ status } })
74
+ }
75
+ # +--------+----------------------------+-----------+-------------+
76
+ # | :city | :in_that_city | :how_many | :avg_status |
77
+ # +--------+----------------------------+-----------+-------------+
78
+ # | London | +------+-------+---------+ | 2 | 20.000 |
79
+ # | | | :sid | :name | :status | | | |
80
+ # | | +------+-------+---------+ | | |
81
+ # | | | S1 | Smith | 20 | | | |
82
+ # | | | S4 | Clark | 20 | | | |
83
+ # | | +------+-------+---------+ | | |
84
+ # | Paris | +------+-------+---------+ | 2 | 20.000 |
85
+ # | | | :sid | :name | :status | | | |
86
+ # | | +------+-------+---------+ | | |
87
+ # | | | S2 | Jones | 10 | | | |
88
+ # | | | S3 | Blake | 30 | | | |
89
+ # | | +------+-------+---------+ | | |
90
+ # | Athens | +------+-------+---------+ | 1 | 30.000 |
91
+ # | | | :sid | :name | :status | | | |
92
+ # | | +------+-------+---------+ | | |
93
+ # | | | S5 | Adams | 30 | | | |
94
+ # | | +------+-------+---------+ | | |
95
+ # +--------+----------------------------+-----------+-------------+
96
+
97
+ # Now observe that the same result can also be expressed as follows (and can be
98
+ # optimized more easily)
99
+ summarized = db.query{
100
+ summary = summarize(:suppliers, [ :city ], how_many: count, avg_status: avg{ status })
101
+ join(grouped, summary)
102
+ }
103
+
104
+ # Oh, and of course...
105
+ require 'json'
106
+ puts summarized.to_json
107
+ # [{"city":"London","in_that_city":[{"sid":"S1","name":"Smith","status":20},{"sid":"S4"...
108
+
109
+ ## Install, bundler, require
110
+
111
+ % [sudo] gem install alf [fastercsv, ...]
112
+ % alf --help
113
+
114
+ # API is not considered stable enough for now, please use
115
+ gem "alf", "= 0.13.0"
116
+
117
+ # The following should not break your code, but is a bit less safe,
118
+ # until 1.0.0 has been reached
119
+ gem "alf", "~> 0.13.0"
771
120
 
772
121
  ## Related Work & Tools
773
122
 
774
- - You should certainly have a look at the Third Manifesto website: {http://www.thethirdmanifesto.com/}
775
- - Why not reading the {http://www.dcs.warwick.ac.uk/~hugh/TTM/DBE-Chapter01.pdf
776
- third manifesto paper} itself?
777
- - Also have a look at {http://www.dcs.warwick.ac.uk/~hugh/TTM/Projects.html other
778
- implementation projects}, especially {http://dbappbuilder.sourceforge.net/Rel.php Rel}
779
- which provides an implementation of the **Tutorial D** language.
780
- - {https://github.com/dkubb/veritas Dan Kubb's Veritas} project is worth considering
123
+ - You should certainly have a look at the
124
+ [Third Manifesto website](http://www.thethirdmanifesto.com/):
125
+ - Why not reading the
126
+ [third manifesto](http://www.dcs.warwick.ac.uk/~hugh/TTM/DBE-Chapter01.pdf) ?
127
+ - Also have a look at
128
+ [other implementation projects](http://www.dcs.warwick.ac.uk/~hugh/TTM/Projects.html)
129
+ especially [Rel](http://dbappbuilder.sourceforge.net/Rel.php) which provides an
130
+ implementation of the **Tutorial D** language.
131
+ - [Dan Kubb's Veritas](https://github.com/dkubb/veritas) project is worth considering
781
132
  also in the Ruby community. While very similar to Alf in providing a pure ruby
782
133
  algebra implementation, Veritas mostly provides a framework for manipulating
783
- and statically analyzing algebra expressions so as to be able to
784
- {https://github.com/dkubb/veritas-optimizer optimize them} and
785
- {https://github.com/dkubb/veritas-sql-generator compile them to SQL}. We are
786
- working together with Dan Kubb to see how Alf and Veritas could be closer from
787
- each other in the future, if not in their codebase, at least in using the very
788
- same terminology for the same concepts.
789
-
790
- ## Contributing
134
+ and statically analyzing algebra expressions so as to be able to
135
+ [optimize them](https://github.com/dkubb/veritas-optimizer) and
136
+ [compile them to SQL](https://github.com/dkubb/veritas-sql-generator).
791
137
 
792
- ### Alf is open source
138
+ ## Contributing
793
139
 
794
- You know the rules:
140
+ You know the rules:
795
141
 
796
142
  * The code is on github https://github.com/blambeau/alf
797
143
  * Please report any problem or bug in the issue tracker on github
@@ -800,67 +146,51 @@ You know the rules:
800
146
  Alf is distributed under a MIT licence. Please let me know if it does not fit
801
147
  your needs and I'll see what I can do!
802
148
 
803
- ### Internals -- Tribute to Sinatra
804
-
805
- Alf's code style is very inspired from what I've found in Sinatra when looking
806
- at its internals a few months ago. Alf, as Sinatra, is mostly implemented in a
807
- single file, lib/alf.rb. Everything is there except specific third-party contributions
808
- (in lib/alf/...). You'll need an editor or IDE that supports code folding/unfolding.
809
- Then, follow the guide:
810
-
811
- 1. Fold everything but the Alf module.
812
- 2. Main concepts, first level of abstraction, should fit on the screen
813
- 3. Unfold the concept you're interested in, and return to the previous bullet
814
-
815
- ### Roadmap
149
+ ## Roadmap
816
150
 
817
151
  Below is what I've imagined about Alf's future. However, this is to be interpreted
818
152
  as my own wish list, while I would love hearing yours instead.
819
153
 
820
- - Towards 1.0.0, I would like to stabilize and document Alf public APIs as well
154
+ - Towards 1.0.0, I would like to stabilize and document Alf public APIs as well
821
155
  as internals (a few concepts are still unstable there). Alf also has a certain
822
156
  number of limitations that are worth overcoming for version 1.0.0. The latter
823
- include the semantically wrong way of applying joins on sub-relations, the
157
+ include the semantically wrong way of applying joins on sub-relations, the
824
158
  impossibility to use Lispy expressions on sub-relations in extend, and the error
825
159
  management which is unspecific and unfriendly so far.
826
- - I also would like starting collecting Reader, Renderer and Environment
827
- contributions for common data sources (SQL, NoSQL, CSV, LOGS) and output
828
- formats (HTML, XML, JSON). Contributions could be either developped as different
829
- gem projects or distributed with Alf's gem and source code, I still need to
160
+ - I also would like starting collecting Reader, Renderer and Connection
161
+ contributions for common data sources (SQL, NoSQL, CSV, LOGS) and output
162
+ formats (HTML, XML, JSON). Contributions could be either developped as different
163
+ gem projects or distributed with Alf's gem and source code, I still need to
830
164
  decide the exact policy (suggestions are more than welcome here)
831
165
  - Alf will remain a practical tool before everything else. In the middle term,
832
166
  I would like to complete the set of available operators (relational and non-
833
- relational ones). Some of them will be operators described in D & D books
834
- while others will be new suggestions of mine.
835
- - In the long term Alf should be able to avoid loading tuples in memory (under
836
- a certain number of conditions on datasources) for almost all queries.
837
- - Without targetting a fast tool at all, I also would like Alf to provide a basic
838
- optimizer that would be able to push equality restrictions down and materialize
839
- sub-expressions used more than once in with expressions.
167
+ relational ones). Some of them will be operators described in D & D books
168
+ while others will be new suggestions of mine.
169
+ - In the long term Alf should be able to avoid loading tuples in memory (under
170
+ a certain number of conditions on datasources) for almost all queries.
171
+ - Without targetting a fast tool at all, I also would like Alf to provide a basic
172
+ optimizer that would be able to push equality restrictions down and materialize
173
+ sub-expressions used more than once in with expressions.
840
174
 
841
- ### Versioning policy
175
+ ## Versioning policy
842
176
 
843
- Alf respects {http://semver.org/ semantic versioning}, which means that it has
177
+ Alf respects [semantic versioning](http://semver.org/), which means that it has
844
178
  a X.Y.Z version number and follows a few rules.
845
179
 
846
- - The public API is made of the commandline tool, the Lispy dialect and the
847
- Relation datastructure. This API will become stable with version 1.0.0 in a
180
+ - The public API is made of the commandline tool, the Lispy dialect and the
181
+ Relation datastructure. This API will become stable with version 1.0.0 in a
848
182
  near future.
849
- - Currently, version 1.0.0 **has not been reached**. It means that **anything
850
- may change at any time**. Best effort will be done to upgrade Y when backward
183
+ - Currently, version 1.0.0 **has not been reached**. It means that **anything
184
+ may change at any time**. Best effort will be done to upgrade Y when backward
851
185
  incompatible changes occur.
852
186
  - Once 1.0.0 will be reached, the following rules will be followed:
853
- - Backward compatible bug fixes will increase Z.
854
- - New features and enhancements that do not break backward compatibility of
187
+ - Backward compatible bug fixes will increase Z.
188
+ - New features and enhancements that do not break backward compatibility of
855
189
  the public API will increase the Y number.
856
- - Non backward compatible changes of the public API will increase the X
190
+ - Non backward compatible changes of the public API will increase the X
857
191
  number.
858
192
 
859
- All classes and modules but Alf module, the Lispy DSL and Alf::Relation are part
193
+ All classes and modules but Alf module, the Lispy DSL and Alf::Relation are part
860
194
  of the private API and may change at any time. A best-effort strategy is followed
861
195
  to avoid breaking internals on tiny (Z) version increases, especially extension
862
- points like Reader and Renderer.
863
-
864
- ## Enjoy Alf!
865
-
866
- - No problem dude!
196
+ points like Reader and Renderer.