arel_ruby 0.0.1 → 0.1.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.
data/README.md CHANGED
@@ -18,7 +18,19 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- See examples
21
+ This gem adds `to_ruby` method onto ARel.
22
+ The `to_ruby` method transforms ARel AST into pure Ruby Enumerable manipulations, so that you can execute queries without using any RDBMS engine.
23
+ Try this on your Rails app and you will realize what's actually gonna happen.
24
+
25
+ YourActiveRecordModel.where(name: 'foo').to_ruby.to_source
26
+ YourActiveRecordModel.order('id').to_ruby.to_source
27
+ YourActiveRecordModel.offset(10).limit(5).to_ruby.to_source
28
+ YourActiveRecordModel.group('created_at').to_ruby.to_source
29
+
30
+
31
+ ## Examples
32
+
33
+ See examples directory
22
34
 
23
35
  ## Contributing
24
36
 
@@ -3,8 +3,8 @@ module ActiveRecord
3
3
  def exec_queries_in_ruby
4
4
  return @records if loaded?
5
5
  ruby = build_arel.to_ruby
6
- connection.send(:log, ruby, 'RUBY') do
7
- self.klass.all.instance_eval ruby
6
+ connection.send(:log, ruby.to_source, 'RUBY') do
7
+ ruby.call self.klass.all
8
8
  end
9
9
  end
10
10
  end
@@ -6,7 +6,6 @@ module Arel
6
6
  class Ruby < Arel::Visitors::Visitor
7
7
  def initialize
8
8
  @connection = Object.new.extend(ActiveRecord::ConnectionAdapters::Quoting)
9
- @chains = []
10
9
  @dummy_column = Struct.new(:type).new
11
10
  end
12
11
 
@@ -36,28 +35,34 @@ module Arel
36
35
  # end
37
36
 
38
37
  def visit_Arel_Nodes_SelectStatement o
39
- [
40
- o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
41
- ("#{o.orders.map { |x| visit_Arel_Nodes_OrderCore x }.join('.')}" unless o.orders.empty?),
42
- (visit(o.offset) if o.offset),
43
- (visit(o.limit) if o.limit),
44
- o.cores.map { |x| x.groups.map { |x| visit x}.join '.' }.flatten.join,
45
- ].compact.delete_if {|e| e.respond_to?(:empty?) && e.empty? }.join '.'
38
+ ProcWithSourceCollection.new([
39
+ o.cores.map { |x| visit_Arel_Nodes_SelectCore x },
40
+ (o.orders.map { |x| visit_Arel_Nodes_OrderCore x } unless o.orders.empty?),
41
+ (visit(o.offset) if o.offset),
42
+ (visit(o.limit) if o.limit),
43
+ o.cores.map { |x| x.groups.map { |x| visit x} },
44
+ ])
46
45
  end
47
46
 
48
47
  def visit_Arel_Nodes_SelectCore o
49
48
  [
50
49
  # ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?),
51
50
  # (visit(o.source) if o.source && !o.source.empty?),
52
- ("#{o.wheres.map { |x| visit x }.join '.' }" unless o.wheres.empty?),
51
+ (o.wheres.map { |x| visit x } unless o.wheres.empty?)
53
52
  # (visit(o.having) if o.having),
54
- ].compact.join '.'
55
- end
53
+ ]
54
+ end
56
55
 
57
56
  def visit_Arel_Nodes_OrderCore order
58
- order.split(',').map do |o|
57
+ #FIXME order_by('a, b') shouldn't actaully be sort_by(&:a).sort_by(&:b)
58
+ order.split(',').map(&:strip).map do |o|
59
59
  attr, direction = o.split(/\s+/)
60
- "sort_by(&:#{visit attr})#{'.reverse' if direction == 'desc'}"
60
+ v = visit attr
61
+ ProcWithSource.new("sort_by(&:#{v})#{'.reverse' if direction == 'desc'}") do |collection|
62
+ col = collection.sort_by {|c| c.send v}
63
+ col.reverse! if direction == 'desc'
64
+ col
65
+ end
61
66
  end
62
67
  end
63
68
 
@@ -116,11 +121,13 @@ module Arel
116
121
  # end
117
122
 
118
123
  def visit_Arel_Nodes_Offset o
119
- "from(#{visit o.expr})"
124
+ v = visit o.expr
125
+ ProcWithSource.new("from(#{v})") {|collection| collection.from(v) }
120
126
  end
121
127
 
122
128
  def visit_Arel_Nodes_Limit o
123
- "take(#{visit o.expr})"
129
+ v = visit o.expr
130
+ ProcWithSource.new("take(#{v})") {|collection| collection.take(v) }
124
131
  end
125
132
 
126
133
  # def visit_Arel_Nodes_Grouping o
@@ -133,7 +140,8 @@ module Arel
133
140
  # end
134
141
 
135
142
  def visit_Arel_Nodes_Group o
136
- "group_by {|g| g.#{visit o.expr}}"
143
+ v = visit o.expr
144
+ ProcWithSource.new("group_by {|g| g.#{v} }") {|collection| collection.group_by {|g| g.send v } }
137
145
  end
138
146
 
139
147
  # def visit_Arel_Nodes_NamedFunction o
@@ -210,7 +218,7 @@ module Arel
210
218
  # end
211
219
 
212
220
  def visit_Arel_Nodes_And o
213
- o.children.map { |x| "select {|o| #{visit x}}"}.join '.'
221
+ o.children.map { |x| ProcWithSource.new("select {|o| o.#{visit(x).to_source}}") { |collection| collection.select {|obj| visit(x).call(obj) } } }
214
222
  end
215
223
 
216
224
  # def visit_Arel_Nodes_Or o
@@ -220,7 +228,8 @@ module Arel
220
228
  # end
221
229
 
222
230
  def visit_Arel_Nodes_Equality o
223
- "#{visit o.left} == #{visit o.right}"
231
+ l, r = visit(o.left), visit(o.right)
232
+ ProcWithSource.new("#{l} == #{r}") { |o| o.send(l) == r }
224
233
  end
225
234
 
226
235
  # def visit_Arel_Nodes_NotEqual o
@@ -234,7 +243,7 @@ module Arel
234
243
 
235
244
 
236
245
  def visit_Arel_Attributes_Attribute o
237
- "o.#{o.name}"
246
+ o.name
238
247
  end
239
248
  alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
240
249
  alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
@@ -251,7 +260,8 @@ module Arel
251
260
  alias :visit_Fixnum :literal
252
261
 
253
262
  def quoted o
254
- quote o
263
+ # don't actually quote...
264
+ o
255
265
  end
256
266
 
257
267
  alias :visit_ActiveSupport_Multibyte_Chars :quoted
@@ -278,13 +288,43 @@ module Arel
278
288
  # alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
279
289
  # alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
280
290
 
281
- # def visit_Array o
282
- # o.map { |x| visit x }.join(', ')
283
- # end
291
+ def visit_Array o
292
+ o.map { |x| visit x }
293
+ end
284
294
 
285
295
  def quote value
286
296
  @connection.quote value, @dummy_column
287
297
  end
288
298
  end
299
+
300
+ class ProcWithSource
301
+ def initialize(source, &block)
302
+ @source, @block = source, block
303
+ end
304
+
305
+ def call(*args)
306
+ @block.call(*args)
307
+ end
308
+
309
+ def to_source
310
+ @source
311
+ end
312
+ end
313
+
314
+ class ProcWithSourceCollection
315
+ def initialize(procs)
316
+ @procs = procs.flatten.compact
317
+ end
318
+
319
+ def call(collection)
320
+ @procs.inject(collection) do |result, lmd|
321
+ lmd.call result
322
+ end
323
+ end
324
+
325
+ def to_source
326
+ @procs.map(&:to_source).join('.')
327
+ end
328
+ end
289
329
  end
290
330
  end
@@ -1,3 +1,3 @@
1
1
  module ArelRuby
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arel_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-06 00:00:00.000000000 Z
12
+ date: 2012-07-13 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ARel Ruby visitor
15
15
  email: