alf 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +42 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +769 -0
  7. data/Rakefile +23 -0
  8. data/TODO.md +26 -0
  9. data/alf.gemspec +191 -0
  10. data/alf.noespec +30 -0
  11. data/bin/alf +31 -0
  12. data/examples/autonum.alf +6 -0
  13. data/examples/cities.rash +4 -0
  14. data/examples/clip.alf +3 -0
  15. data/examples/compact.alf +2 -0
  16. data/examples/database.alf +6 -0
  17. data/examples/defaults.alf +3 -0
  18. data/examples/extend.alf +3 -0
  19. data/examples/group.alf +3 -0
  20. data/examples/intersect.alf +4 -0
  21. data/examples/join.alf +2 -0
  22. data/examples/minus.alf +8 -0
  23. data/examples/nest.alf +2 -0
  24. data/examples/nulls.rash +3 -0
  25. data/examples/parts.rash +6 -0
  26. data/examples/project.alf +2 -0
  27. data/examples/quota.alf +4 -0
  28. data/examples/rename.alf +3 -0
  29. data/examples/restrict.alf +2 -0
  30. data/examples/runall.sh +26 -0
  31. data/examples/schema.yaml +28 -0
  32. data/examples/sort.alf +4 -0
  33. data/examples/summarize.alf +16 -0
  34. data/examples/suppliers.rash +5 -0
  35. data/examples/supplies.rash +12 -0
  36. data/examples/ungroup.alf +4 -0
  37. data/examples/union.alf +3 -0
  38. data/examples/unnest.alf +4 -0
  39. data/examples/with.alf +23 -0
  40. data/lib/alf.rb +2984 -0
  41. data/lib/alf/loader.rb +1 -0
  42. data/lib/alf/renderer/text.rb +153 -0
  43. data/lib/alf/renderer/yaml.rb +22 -0
  44. data/lib/alf/version.rb +14 -0
  45. data/spec/aggregator_spec.rb +62 -0
  46. data/spec/alf_spec.rb +47 -0
  47. data/spec/assumptions_spec.rb +15 -0
  48. data/spec/environment/explicit_spec.rb +15 -0
  49. data/spec/environment/folder_spec.rb +30 -0
  50. data/spec/examples_spec.rb +26 -0
  51. data/spec/lispy_spec.rb +23 -0
  52. data/spec/operator/command_methods_spec.rb +38 -0
  53. data/spec/operator/non_relational/autonum_spec.rb +61 -0
  54. data/spec/operator/non_relational/clip_spec.rb +49 -0
  55. data/spec/operator/non_relational/compact/buffer_based.rb +30 -0
  56. data/spec/operator/non_relational/compact/sort_based_spec.rb +30 -0
  57. data/spec/operator/non_relational/compact_spec.rb +38 -0
  58. data/spec/operator/non_relational/defaults_spec.rb +55 -0
  59. data/spec/operator/non_relational/sort_spec.rb +66 -0
  60. data/spec/operator/relational/extend_spec.rb +34 -0
  61. data/spec/operator/relational/group_spec.rb +54 -0
  62. data/spec/operator/relational/intersect_spec.rb +58 -0
  63. data/spec/operator/relational/join/hash_based_spec.rb +63 -0
  64. data/spec/operator/relational/minus_spec.rb +56 -0
  65. data/spec/operator/relational/nest_spec.rb +32 -0
  66. data/spec/operator/relational/project_spec.rb +65 -0
  67. data/spec/operator/relational/quota_spec.rb +44 -0
  68. data/spec/operator/relational/rename_spec.rb +32 -0
  69. data/spec/operator/relational/restrict_spec.rb +56 -0
  70. data/spec/operator/relational/summarize/sort_based_spec.rb +31 -0
  71. data/spec/operator/relational/summarize_spec.rb +41 -0
  72. data/spec/operator/relational/ungroup_spec.rb +35 -0
  73. data/spec/operator/relational/union_spec.rb +35 -0
  74. data/spec/operator/relational/unnest_spec.rb +32 -0
  75. data/spec/reader/alf_file_spec.rb +15 -0
  76. data/spec/reader/input.rb +2 -0
  77. data/spec/reader/rash_spec.rb +31 -0
  78. data/spec/reader_spec.rb +27 -0
  79. data/spec/renderer/text/cell_spec.rb +34 -0
  80. data/spec/renderer/text/row_spec.rb +30 -0
  81. data/spec/renderer/text/table_spec.rb +39 -0
  82. data/spec/renderer_spec.rb +42 -0
  83. data/spec/spec_helper.rb +26 -0
  84. data/spec/tools/ordering_key_spec.rb +81 -0
  85. data/spec/tools/projection_key_spec.rb +83 -0
  86. data/spec/tools/tools_spec.rb +25 -0
  87. data/spec/tools/tuple_handle_spec.rb +78 -0
  88. data/tasks/debug_mail.rake +78 -0
  89. data/tasks/debug_mail.txt +13 -0
  90. data/tasks/gem.rake +68 -0
  91. data/tasks/spec_test.rake +79 -0
  92. data/tasks/unit_test.rake +77 -0
  93. data/tasks/yard.rake +51 -0
  94. metadata +282 -0
@@ -0,0 +1,23 @@
1
+ begin
2
+ gem "bundler", "~> 1.0"
3
+ require "bundler/setup"
4
+ rescue LoadError => ex
5
+ puts ex.message
6
+ abort "Bundler failed to load, (did you run 'gem install bundler' ?)"
7
+ end
8
+
9
+ # Dynamically load the gem spec
10
+ $gemspec_file = File.expand_path('../alf.gemspec', __FILE__)
11
+ $gemspec = Kernel.eval(File.read($gemspec_file))
12
+
13
+ # We run tests by default
14
+ task :default => :test
15
+
16
+ #
17
+ # Install all tasks found in tasks folder
18
+ #
19
+ # See .rake files there for complete documentation.
20
+ #
21
+ Dir["tasks/*.rake"].each do |taskfile|
22
+ instance_eval File.read(taskfile), taskfile
23
+ end
data/TODO.md ADDED
@@ -0,0 +1,26 @@
1
+ * RENAME: add prefix, suffix and lambda renaming
2
+
3
+ (rename :suppliers, [:name, :city], :prefix => "supplier_")
4
+ (rename :suppliers, [:name, :city], :suffix => "_sup")
5
+ (rename :suppliers, [:name, :city], lambda{|name| name.upcase})
6
+
7
+ * NEST: provide a multi-nesting ability?
8
+
9
+ (nest (nest :supplies, [:a, :b], :x), [:x, :c], :y)
10
+ => (nest :supplies, :x => [:a, :b], :y => [:x, :c])
11
+
12
+ But this would only work with Ruby 1.9 as the hash order would be important
13
+ as such
14
+
15
+ * GROUP: provide a multi-grouping ability?
16
+
17
+ Similar to nest, with same limitation.
18
+
19
+ * Add PIVOT and UNPIVOT operators
20
+
21
+ * Add MATCHING, NOT_MATCHING
22
+
23
+ * Add a to_ruby abstraction and replace inspect usages in TupleHandle and
24
+ Rash renderer
25
+
26
+ * Find a way to complete the description of Quota...
@@ -0,0 +1,191 @@
1
+ # We require your library, mainly to have access to the VERSION number.
2
+ # Feel free to set $version manually.
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require "alf/version"
5
+ $version = Alf::Version.to_s
6
+
7
+ #
8
+ # This is your Gem specification. Default values are provided so that your library
9
+ # should be correctly packaged given what you have described in the .noespec file.
10
+ #
11
+ Gem::Specification.new do |s|
12
+
13
+ ################################################################### ABOUT YOUR GEM
14
+
15
+ # Gem name (required)
16
+ s.name = "alf"
17
+
18
+ # Gem version (required)
19
+ s.version = $version
20
+
21
+ # A short summary of this gem
22
+ #
23
+ # This is displayed in `gem list -d`.
24
+ s.summary = "Classy data-manipulation dressed in a DSL (+ commandline)"
25
+
26
+ # A long description of this gem (required)
27
+ #
28
+ # The description should be more detailed than the summary. For example,
29
+ # you might wish to copy the entire README into the description.
30
+ s.description = "Alf is a commandline tool and Ruby library to manipulate data with all the \npower of a truly relational algebra approach. "
31
+
32
+ # The URL of this gem home page (optional)
33
+ s.homepage = "http://rubydoc.info/github/blambeau/alf/master/frames"
34
+
35
+ # Gem publication date (required but auto)
36
+ #
37
+ # Today is automatically used by default, uncomment only if
38
+ # you know what you do!
39
+ #
40
+ # s.date = Time.now.strftime('%Y-%m-%d')
41
+
42
+ # The license(s) for the library. Each license must be a short name, no
43
+ # more than 64 characters.
44
+ #
45
+ # s.licences = %w{}
46
+
47
+ # The rubyforge project this gem lives under (optional)
48
+ #
49
+ # s.rubyforge_project = nil
50
+
51
+ ################################################################### ABOUT THE AUTHORS
52
+
53
+ # The list of author names who wrote this gem.
54
+ #
55
+ # If you are providing multiple authors and multiple emails they should be
56
+ # in the same order.
57
+ #
58
+ s.authors = ["Bernard Lambeau"]
59
+
60
+ # Contact emails for this gem
61
+ #
62
+ # If you are providing multiple authors and multiple emails they should be
63
+ # in the same order.
64
+ #
65
+ # NOTE: Somewhat strangly this attribute is always singular!
66
+ # Don't replace by s.emails = ...
67
+ s.email = ["blambeau@gmail.com"]
68
+
69
+ ################################################################### PATHS, FILES, BINARIES
70
+
71
+ # Paths in the gem to add to $LOAD_PATH when this gem is
72
+ # activated (required).
73
+ #
74
+ # The default 'lib' is typically sufficient.
75
+ s.require_paths = ["lib"]
76
+
77
+ # Files included in this gem.
78
+ #
79
+ # By default, we take all files included in the Manifest.txt file on root
80
+ # of the project. Entries of the manifest are interpreted as Dir[...]
81
+ # patterns so that lazy people may use wilcards like lib/**/*
82
+ #
83
+ here = File.expand_path(File.dirname(__FILE__))
84
+ s.files = File.readlines(File.join(here, 'Manifest.txt')).
85
+ inject([]){|files, pattern| files + Dir[File.join(here, pattern.strip)]}.
86
+ collect{|x| x[(1+here.size)..-1]}
87
+
88
+ # Test files included in this gem.
89
+ #
90
+ s.test_files = Dir["test/**/*"] + Dir["spec/**/*"]
91
+
92
+ # The path in the gem for executable scripts (optional)
93
+ #
94
+ s.bindir = "bin"
95
+
96
+ # Executables included in the gem.
97
+ #
98
+ s.executables = (Dir["bin/*"]).collect{|f| File.basename(f)}
99
+
100
+ ################################################################### REQUIREMENTS & INSTALL
101
+ # Remember the gem version requirements operators and schemes:
102
+ # = Equals version
103
+ # != Not equal to version
104
+ # > Greater than version
105
+ # < Less than version
106
+ # >= Greater than or equal to
107
+ # <= Less than or equal to
108
+ # ~> Approximately greater than
109
+ #
110
+ # Don't forget to have a look at http://lmgtfy.com/?q=Ruby+Versioning+Policies
111
+ # for setting your gem version.
112
+ #
113
+ # For your requirements to other gems, remember that
114
+ # ">= 2.2.0" (optimistic: specify minimal version)
115
+ # ">= 2.2.0", "< 3.0" (pessimistic: not greater than the next major)
116
+ # "~> 2.2" (shortcut for ">= 2.2.0", "< 3.0")
117
+ # "~> 2.2.0" (shortcut for ">= 2.2.0", "< 2.3.0")
118
+ #
119
+
120
+ #
121
+ # One call to add_dependency('gem_name', 'gem version requirement') for each
122
+ # runtime dependency. These gems will be installed with your gem.
123
+ # One call to add_development_dependency('gem_name', 'gem version requirement')
124
+ # for each development dependency. These gems are required for developers
125
+ #
126
+ s.add_development_dependency("rake", "~> 0.8.7")
127
+ s.add_development_dependency("bundler", "~> 1.0")
128
+ s.add_development_dependency("rspec", "~> 2.6.0")
129
+ s.add_development_dependency("yard", "~> 0.7.2")
130
+ s.add_development_dependency("bluecloth", "~> 2.0.9")
131
+ s.add_development_dependency("wlang", "~> 0.10.1")
132
+ s.add_development_dependency("noe", "~> 1.3.0")
133
+ s.add_dependency("quickl", "~> 0.2.1")
134
+
135
+ # The version of ruby required by this gem
136
+ #
137
+ # Uncomment and set this if your gem requires specific ruby versions.
138
+ #
139
+ # s.required_ruby_version = ">= 0"
140
+
141
+ # The RubyGems version required by this gem
142
+ #
143
+ # s.required_rubygems_version = ">= 0"
144
+
145
+ # The platform this gem runs on. See Gem::Platform for details.
146
+ #
147
+ # s.platform = nil
148
+
149
+ # Extensions to build when installing the gem.
150
+ #
151
+ # Valid types of extensions are extconf.rb files, configure scripts
152
+ # and rakefiles or mkrf_conf files.
153
+ #
154
+ s.extensions = []
155
+
156
+ # External (to RubyGems) requirements that must be met for this gem to work.
157
+ # It’s simply information for the user.
158
+ #
159
+ s.requirements = nil
160
+
161
+ # A message that gets displayed after the gem is installed
162
+ #
163
+ # Uncomment and set this if you want to say something to the user
164
+ # after gem installation
165
+ #
166
+ s.post_install_message = nil
167
+
168
+ ################################################################### SECURITY
169
+
170
+ # The key used to sign this gem. See Gem::Security for details.
171
+ #
172
+ # s.signing_key = nil
173
+
174
+ # The certificate chain used to sign this gem. See Gem::Security for
175
+ # details.
176
+ #
177
+ # s.cert_chain = []
178
+
179
+ ################################################################### RDOC
180
+
181
+ # An ARGV style array of options to RDoc
182
+ #
183
+ # See 'rdoc --help' about this
184
+ #
185
+ s.rdoc_options = []
186
+
187
+ # Extra files to add to RDoc such as README
188
+ #
189
+ s.extra_rdoc_files = Dir["README.md"] + Dir["CHANGELOG.md"] + Dir["LICENCE.md"]
190
+
191
+ end
@@ -0,0 +1,30 @@
1
+ template-info:
2
+ name: "ruby"
3
+ version: 1.3.0
4
+ variables:
5
+ lower:
6
+ alf
7
+ upper:
8
+ Alf
9
+ version:
10
+ 0.9.0
11
+ summary: |-
12
+ Classy data-manipulation dressed in a DSL (+ commandline)
13
+ description: |-
14
+ Alf is a commandline tool and Ruby library to manipulate data with all the
15
+ power of a truly relational algebra approach.
16
+ authors:
17
+ - {name: Bernard Lambeau, email: blambeau@gmail.com}
18
+ links:
19
+ - http://rubydoc.info/github/blambeau/alf/master/frames
20
+ - http://github.com/blambeau/alf
21
+ dependencies:
22
+ - {name: rake, version: "~> 0.8.7", groups: [development]}
23
+ - {name: bundler, version: "~> 1.0", groups: [development]}
24
+ - {name: rspec, version: "~> 2.6.0", groups: [development]}
25
+ - {name: yard, version: "~> 0.7.2", groups: [development]}
26
+ - {name: bluecloth, version: "~> 2.0.9", groups: [development]}
27
+ - {name: wlang, version: "~> 0.10.1", groups: [development]}
28
+ - {name: noe, version: "~> 1.3.0", groups: [development]}
29
+ - {name: quickl, version: "~> 0.2.1", groups: [runtime]}
30
+
data/bin/alf ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ module AlfLauncher
3
+
4
+ def self.load
5
+ begin
6
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
+ require "alf"
8
+ rescue LoadError => ex
9
+ require "rubygems"
10
+ require "alf"
11
+ end
12
+ end
13
+
14
+ def self.normalize(args)
15
+ opts = []
16
+ while !args.empty? && (args.first =~ /^\-/)
17
+ opts << args.shift
18
+ end
19
+ if args.empty? or (args.size == 1 && File.exists?(args.first))
20
+ opts << "exec"
21
+ end
22
+ opts += args
23
+ end
24
+
25
+ def self.start(argv)
26
+ load
27
+ Alf::Command::Main.run(normalize(argv), __FILE__)
28
+ end
29
+
30
+ end # module AlfLaucher
31
+ AlfLauncher.start(ARGV)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env alf
2
+ # Autonumber suppliers (:autonum attribute name by default)
3
+ (autonum :suppliers)
4
+
5
+ # You can specify the attribute name
6
+ (autonum :suppliers, :unique_id)
@@ -0,0 +1,4 @@
1
+ {:city => 'London', :country => 'England'}
2
+ {:city => 'Paris', :country => 'France'}
3
+ {:city => 'Athens', :country => 'Greece'}
4
+ {:city => 'Brussels', :country => 'Belgium'}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env alf
2
+ (clip :suppliers, [:name, :city])
3
+ (clip :suppliers, [:name, :city], true)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env alf
2
+ (compact (clip :suppliers, [:city]))
@@ -0,0 +1,6 @@
1
+ [{
2
+ :suppliers => (dataset :suppliers),
3
+ :parts => (dataset :parts),
4
+ :cities => (dataset :cities),
5
+ :supplies => (dataset :supplies)
6
+ }]
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env alf
2
+ (defaults :suppliers, :country => 'Belgium')
3
+ (defaults :suppliers, {:country => 'Belgium'}, true)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env alf
2
+ (extend :supplies, :sp => lambda{ sid + "/" + pid },
3
+ :big => lambda{ qty > 100 ? true : false })
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env alf
2
+ (group :supplies, [:pid, :qty], :supplying)
3
+ (group :supplies, [:sid], :supplying, true)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env alf
2
+ (intersect \
3
+ (restrict :suppliers, lambda{ status >= 20 }),
4
+ (restrict :suppliers, lambda{ city == 'Paris' }))
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env alf
2
+ (join :suppliers, :supplies)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env alf
2
+ # Give all suppliers, except those living in Paris
3
+ (minus :suppliers,
4
+ (restrict :suppliers, lambda{ city == 'Paris' }))
5
+
6
+ # This is a contrived example for illustrating minus, as the
7
+ # following is equivalent
8
+ (restrict :suppliers, lambda{ city != 'Paris' })
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env alf
2
+ (nest :suppliers, [:city, :status], :loc_and_status)
@@ -0,0 +1,3 @@
1
+ {:sid => 'S1', :age => nil}
2
+ {:sid => 'S2', :age => 32}
3
+ {:sid => 'S3', :age => nil}
@@ -0,0 +1,6 @@
1
+ {:pid => 'P1', :name => 'Nut', :color => 'Red', :weight => 12.0, :city => 'London'}
2
+ {:pid => 'P2', :name => 'Bolt', :color => 'Green', :weight => 17.0, :city => 'Paris'}
3
+ {:pid => 'P3', :name => 'Screw', :color => 'Blue', :weight => 17.0, :city => 'Oslo'}
4
+ {:pid => 'P4', :name => 'Screw', :color => 'Red', :weight => 14.0, :city => 'London'}
5
+ {:pid => 'P5', :name => 'Cam', :color => 'Blue', :weight => 12.0, :city => 'Paris'}
6
+ {:pid => 'P6', :name => 'Cog', :color => 'Red', :weight => 19.0, :city => 'London'}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env alf
2
+ (project :suppliers, [:name, :city])
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env alf
2
+ (quota :supplies, [:sid], [:qty],
3
+ :position => Agg::count,
4
+ :sum_qty => Agg::sum(:qty))
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env alf
2
+ (rename :suppliers, :name => :supplier_name,
3
+ :city => :supplier_city)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env alf
2
+ (restrict :suppliers, lambda{ status > 20 })
@@ -0,0 +1,26 @@
1
+ alf --text autonum suppliers
2
+ alf --text autonum suppliers -- unique_id
3
+ alf --text defaults suppliers -- country "'Belgium'"
4
+ alf --text defaults --strict suppliers -- country "'Belgium'"
5
+ alf --text compact suppliers
6
+ alf --text sort suppliers -- name asc
7
+ alf --text sort suppliers -- city desc name asc
8
+ alf --text clip suppliers -- name city
9
+ alf --text clip suppliers --allbut -- name city
10
+ alf --text project suppliers -- name city
11
+ alf --text project --allbut suppliers -- name city
12
+ alf --text extend supplies -- sp 'sid + "/" + pid' big "qty > 100 ? true : false"
13
+ alf --text rename suppliers -- name supplier_name city supplier_city
14
+ alf --text restrict suppliers -- "status > 20"
15
+ alf --text restrict suppliers -- city "'London'"
16
+ alf --text nest suppliers -- city status loc_and_status
17
+ alf --text unnest suppliers -- loc_and_status
18
+ alf --text group supplies -- pid qty supplying
19
+ alf --text group --allbut supplies -- sid supplying
20
+ alf --text ungroup group -- supplying
21
+ alf --text summarize supplies -- --by=sid total_qty "sum(:qty)"
22
+ alf --text quota supplies -- --by=sid --order=qty position count sum_qty "sum(:qty)"
23
+ alf --text join suppliers supplies
24
+ alf --text union suppliers suppliers
25
+ alf --text intersect suppliers suppliers
26
+ alf --text minus suppliers suppliers
@@ -0,0 +1,28 @@
1
+ logical:
2
+ - name: suppliers
3
+ heading:
4
+ - { name: sid, domain: String, mandatory: true }
5
+ - { name: name, domain: String, mandatory: true }
6
+ - { name: status, domain: Integer, mandatory: true }
7
+ - { name: city, domain: String, mandatory: true }
8
+ constraints:
9
+ - { name: pk, type: primary_key, attributes: [ sid ] }
10
+ - name: parts
11
+ heading:
12
+ - { name: pid, domain: String, mandatory: true }
13
+ - { name: name, domain: String, mandatory: true }
14
+ - { name: color, domain: String, mandatory: true }
15
+ - { name: weight, domain: Float, mandatory: true }
16
+ - { name: city, domain: String, mandatory: true }
17
+ constraints:
18
+ - { name: pk, type: primary_key, attributes: [ pid ] }
19
+ - name: supplies
20
+ heading:
21
+ - { name: sid, domain: String, mandatory: true }
22
+ - { name: pid, domain: String, mandatory: true }
23
+ - { name: qty, domain: Integer, mandatory: true }
24
+ constraints:
25
+ - { name: pk, type: primary_key, attributes: [ sid, pid ] }
26
+ - { name: known_supplier, type: foreign_key, attributes: [ sid ], references: suppliers }
27
+ - { name: known_part, type: foreign_key, attributes: [ pid ], references: parts }
28
+