bud 0.0.8 → 0.1.0.pre1
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 +4 -10
 - data/bin/budplot +1 -2
 - data/docs/cheat.md +2 -15
 - data/examples/basics/paths.rb +7 -7
 - data/lib/bud/aggs.rb +15 -19
 - data/lib/bud/bud_meta.rb +165 -77
 - data/lib/bud/bust/bust.rb +11 -4
 - data/lib/bud/collections.rb +643 -280
 - data/lib/bud/depanalysis.rb +50 -25
 - data/lib/bud/executor/elements.rb +592 -0
 - data/lib/bud/executor/group.rb +104 -0
 - data/lib/bud/executor/join.rb +638 -0
 - data/lib/bud/graphs.rb +12 -11
 - data/lib/bud/joins.rb +2 -1
 - data/lib/bud/meta_algebra.rb +5 -4
 - data/lib/bud/metrics.rb +9 -3
 - data/lib/bud/monkeypatch.rb +131 -23
 - data/lib/bud/rebl.rb +41 -28
 - data/lib/bud/rewrite.rb +112 -440
 - data/lib/bud/server.rb +3 -2
 - data/lib/bud/source.rb +109 -0
 - data/lib/bud/state.rb +16 -9
 - data/lib/bud/storage/dbm.rb +62 -16
 - data/lib/bud/storage/zookeeper.rb +2 -2
 - data/lib/bud/viz.rb +8 -4
 - data/lib/bud/viz_util.rb +10 -9
 - data/lib/bud.rb +413 -199
 - metadata +40 -55
 - data/examples/deploy/tokenring-ec2.rb +0 -26
 - data/examples/deploy/tokenring-fork.rb +0 -15
 - data/examples/deploy/tokenring-thread.rb +0 -15
 - data/examples/deploy/tokenring.rb +0 -47
 - data/lib/bud/deploy/deployer.rb +0 -67
 - data/lib/bud/deploy/ec2deploy.rb +0 -199
 - data/lib/bud/deploy/forkdeploy.rb +0 -90
 - data/lib/bud/deploy/threaddeploy.rb +0 -38
 - data/lib/bud/storage/tokyocabinet.rb +0 -190
 - data/lib/bud/stratify.rb +0 -85
 
    
        data/README
    CHANGED
    
    | 
         @@ -10,15 +10,11 @@ documentation. 
     | 
|
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            Main deficiencies at this point are:
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            - Inefficient evaluation: Programs are run using semi-naive evaluation
         
     | 
| 
       14 
     | 
    
         
            -
              strategies, but no further query optimization has been implemented, and little
         
     | 
| 
       15 
     | 
    
         
            -
              effort has been spent in tuning.
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
13 
     | 
    
         
             
            - No Ruby constraints: Within Bloom programs the full power of Ruby is also
         
     | 
| 
       18 
14 
     | 
    
         
             
              available, including mutable state.  This allows programmers to get outside
         
     | 
| 
       19 
15 
     | 
    
         
             
              the Bloom framework and lose cleanliness.
         
     | 
| 
       20 
16 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
            - Compatibility: Bud only works with Ruby (MRI) 1.8 
     | 
| 
      
 17 
     | 
    
         
            +
            - Compatibility: Bud only works with Ruby (MRI) 1.8 and 1.9. JRuby and other
         
     | 
| 
       22 
18 
     | 
    
         
             
              Ruby implementations are currently not supported.
         
     | 
| 
       23 
19 
     | 
    
         | 
| 
       24 
20 
     | 
    
         
             
            ## Installation
         
     | 
| 
         @@ -39,8 +35,6 @@ To run the unit tests: 
     | 
|
| 
       39 
35 
     | 
    
         | 
| 
       40 
36 
     | 
    
         
             
            ## Optional Dependencies
         
     | 
| 
       41 
37 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
            The bud gem has a handful of mandatory dependencies. It also has  
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
            before installing the "tokyocabinet" gem, the Tokyo Cabinet libraries should be
         
     | 
| 
       46 
     | 
    
         
            -
            installed first.
         
     | 
| 
      
 38 
     | 
    
         
            +
            The bud gem has a handful of mandatory dependencies. It also has one optional
         
     | 
| 
      
 39 
     | 
    
         
            +
            dependency: if you wish to use Bud collections backed by Zookeeper, the
         
     | 
| 
      
 40 
     | 
    
         
            +
            "zookeeper" gem must be installed.
         
     | 
    
        data/bin/budplot
    CHANGED
    
    | 
         @@ -2,7 +2,6 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            require 'rubygems'
         
     | 
| 
       3 
3 
     | 
    
         
             
            require 'bud'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'bud/bud_meta'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'bud/depanalysis'
         
     | 
| 
       6 
5 
     | 
    
         
             
            require 'bud/graphs'
         
     | 
| 
       7 
6 
     | 
    
         
             
            require 'bud/meta_algebra'
         
     | 
| 
       8 
7 
     | 
    
         
             
            require 'bud/viz_util'
         
     | 
| 
         @@ -33,7 +32,7 @@ def make_instance(mods) 
     | 
|
| 
       33 
32 
     | 
    
         
             
                  if mods.length == 1
         
     | 
| 
       34 
33 
     | 
    
         
             
                    return mod_klass.new
         
     | 
| 
       35 
34 
     | 
    
         
             
                  else
         
     | 
| 
       36 
     | 
    
         
            -
                    puts "Error: cannot intermix  
     | 
| 
      
 35 
     | 
    
         
            +
                    puts "Error: cannot intermix class \"#{mod_klass}\" with modules"
         
     | 
| 
       37 
36 
     | 
    
         
             
                    exit
         
     | 
| 
       38 
37 
     | 
    
         
             
                  end
         
     | 
| 
       39 
38 
     | 
    
         
             
                elsif mod_klass.class != Module
         
     | 
    
        data/docs/cheat.md
    CHANGED
    
    | 
         @@ -114,13 +114,12 @@ Built-in scratch collection to be used on the lhs of a rule; permanently halts t 
     | 
|
| 
       114 
114 
     | 
    
         
             
            If the item `[:kill]` is inserted, the Bud OS process (including all Bud instances) is also halted.
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
116 
     | 
    
         
             
            ### sync ###
         
     | 
| 
       117 
     | 
    
         
            -
            Persistent collection mapped to an external storage engine, with synchronous write-flushing each timestep.   
     | 
| 
      
 117 
     | 
    
         
            +
            Persistent collection mapped to an external storage engine, with synchronous write-flushing each timestep.  
         
     | 
| 
       118 
118 
     | 
    
         
             
            Default attributes: `[:key] => [:val]`.
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
       120 
120 
     | 
    
         
             
                sync :s1, :dbm
         
     | 
| 
       121 
     | 
    
         
            -
                sync :s2, :tokyo, [:k1, :k2] => [:v1, :v2]
         
     | 
| 
       122 
121 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
      
 122 
     | 
    
         
            +
            Currently only [dbm](http://en.wikipedia.org/wiki/Dbm) is supported. Support for tokyo cabinet present in an earlier release has been removed.<br>
         
     | 
| 
       124 
123 
     | 
    
         | 
| 
       125 
124 
     | 
    
         
             
            ### store ###
         
     | 
| 
       126 
125 
     | 
    
         
             
            Persistent collection mapped to an external storage engine, with asynchronous write-flushing.  Supported storage engines: `:zookeeper`.<br>
         
     | 
| 
         @@ -173,8 +172,6 @@ implicit map: 
     | 
|
| 
       173 
172 
     | 
    
         | 
| 
       174 
173 
     | 
    
         
             
            `flat_map`:
         
     | 
| 
       175 
174 
     | 
    
         | 
| 
       176 
     | 
    
         
            -
                require 'backports' # flat_map not included in Ruby 1.8 by default
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
175 
     | 
    
         
             
                t3 <= bc.flat_map do |t| # unnest a collection-valued attribute
         
     | 
| 
       179 
176 
     | 
    
         
             
                  bc.col4.map { |sub| [t.col1, t.col2, t.col3, sub] }
         
     | 
| 
       180 
177 
     | 
    
         
             
                end
         
     | 
| 
         @@ -323,16 +320,6 @@ The schema of a temp collection in inherited from the rhs; if the rhs has no 
     | 
|
| 
       323 
320 
     | 
    
         
             
            schema, a simple one is manufactured to suit the data found in the rhs at
         
     | 
| 
       324 
321 
     | 
    
         
             
            runtime: `[c0, c1, ...]`.
         
     | 
| 
       325 
322 
     | 
    
         | 
| 
       326 
     | 
    
         
            -
            `with`<br>
         
     | 
| 
       327 
     | 
    
         
            -
            With statements define a temp collection that can be referenced only within the scope of the associated block.  They are useful when you "fork" in a dataflow into two lhs destinations:
         
     | 
| 
       328 
     | 
    
         
            -
             
     | 
| 
       329 
     | 
    
         
            -
                with :biggies <= request {|r| r if r.quantity > 100}, begin
         
     | 
| 
       330 
     | 
    
         
            -
                  to_process <= (biggies * known_good).lefts(:key=>:key)
         
     | 
| 
       331 
     | 
    
         
            -
                  denied <= (biggies * known_good).nopairs(:key=>key)
         
     | 
| 
       332 
     | 
    
         
            -
                end
         
     | 
| 
       333 
     | 
    
         
            -
             
     | 
| 
       334 
     | 
    
         
            -
            The advantage of using `with` over `temp` is modularity: all the rules referencing `biggies` have to be bundled together, making it easier to see that the contents of `request` with quantity > 100 are handled properly.  
         
     | 
| 
       335 
     | 
    
         
            -
             
     | 
| 
       336 
323 
     | 
    
         
             
            ## Bud Modules ##
         
     | 
| 
       337 
324 
     | 
    
         
             
            A Bud module combines state (collections) and logic (Bloom rules). Using modules allows your program to be decomposed into a collection of smaller units.
         
     | 
| 
       338 
325 
     | 
    
         | 
    
        data/examples/basics/paths.rb
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # simple shortest paths
         
     | 
| 
       2 
     | 
    
         
            -
            # note use of program.tick at bottom to run a single  
     | 
| 
      
 2 
     | 
    
         
            +
            # note use of program.tick at bottom to run a single timestep
         
     | 
| 
       3 
3 
     | 
    
         
             
            # and inspect relations
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'rubygems'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'bud'
         
     | 
| 
         @@ -9,19 +9,19 @@ class ShortestPaths 
     | 
|
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
              state do
         
     | 
| 
       11 
11 
     | 
    
         
             
                table :link, [:from, :to, :cost]
         
     | 
| 
       12 
     | 
    
         
            -
                table :path, [:from, :to, : 
     | 
| 
       13 
     | 
    
         
            -
                table :shortest, [:from, :to] => [: 
     | 
| 
      
 12 
     | 
    
         
            +
                table :path, [:from, :to, :nxt, :cost]
         
     | 
| 
      
 13 
     | 
    
         
            +
                table :shortest, [:from, :to] => [:nxt, :cost]
         
     | 
| 
       14 
14 
     | 
    
         
             
              end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
              # recursive rules to define all paths from links
         
     | 
| 
       17 
17 
     | 
    
         
             
              bloom :make_paths do
         
     | 
| 
       18 
18 
     | 
    
         
             
                # base case: every link is a path
         
     | 
| 
       19 
     | 
    
         
            -
                path <= link {| 
     | 
| 
      
 19 
     | 
    
         
            +
                path <= link {|l| [l.from, l.to, l.to, l.cost]}
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                # inductive case: make path of length n+1 by connecting a link to a path of
         
     | 
| 
       22 
22 
     | 
    
         
             
                # length n
         
     | 
| 
       23 
23 
     | 
    
         
             
                path <= (link*path).pairs(:to => :from) do |l,p|
         
     | 
| 
       24 
     | 
    
         
            -
                  [l.from, p.to,  
     | 
| 
      
 24 
     | 
    
         
            +
                  [l.from, p.to, l.to, l.cost+p.cost]
         
     | 
| 
       25 
25 
     | 
    
         
             
                end
         
     | 
| 
       26 
26 
     | 
    
         
             
              end
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
         @@ -43,11 +43,11 @@ program.link <= [['a', 'b', 1], 
     | 
|
| 
       43 
43 
     | 
    
         
             
                             ['d', 'e', 1]]
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
45 
     | 
    
         
             
            program.tick # one timestamp is enough for this simple program
         
     | 
| 
       46 
     | 
    
         
            -
            program.shortest.sort.each {|t| puts t.inspect}
         
     | 
| 
      
 46 
     | 
    
         
            +
            program.shortest.to_a.sort.each {|t| puts t.inspect}
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
            puts "----"
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
            # now lets add an extra link and recompute
         
     | 
| 
       51 
51 
     | 
    
         
             
            program.link << ['e', 'f', 1]
         
     | 
| 
       52 
52 
     | 
    
         
             
            program.tick
         
     | 
| 
       53 
     | 
    
         
            -
            program.shortest.sort.each {|t| puts t.inspect}
         
     | 
| 
      
 53 
     | 
    
         
            +
            program.shortest.to_a.sort.each {|t| puts t.inspect}
         
     | 
    
        data/lib/bud/aggs.rb
    CHANGED
    
    | 
         @@ -11,7 +11,7 @@ module Bud 
     | 
|
| 
       11 
11 
     | 
    
         
             
                #     a. :ignore tells the caller to ignore this input
         
     | 
| 
       12 
12 
     | 
    
         
             
                #     b. :keep tells the caller to save this input
         
     | 
| 
       13 
13 
     | 
    
         
             
                #     c. :replace tells the caller to keep this input alone
         
     | 
| 
       14 
     | 
    
         
            -
                #     d.  
     | 
| 
      
 14 
     | 
    
         
            +
                #     d. :delete, [t1, t2, ...] tells the caller to delete the remaining tuples
         
     | 
| 
       15 
15 
     | 
    
         
             
                #  For things that do not descend from ArgExemplary, the 2nd part can simply be nil.
         
     | 
| 
       16 
16 
     | 
    
         
             
                def trans(the_state, val)
         
     | 
| 
       17 
17 
     | 
    
         
             
                  return the_state, :ignore
         
     | 
| 
         @@ -42,6 +42,8 @@ module Bud 
     | 
|
| 
       42 
42 
     | 
    
         
             
                def trans(the_state, val)
         
     | 
| 
       43 
43 
     | 
    
         
             
                  if the_state < val 
         
     | 
| 
       44 
44 
     | 
    
         
             
                    return the_state, :ignore
         
     | 
| 
      
 45 
     | 
    
         
            +
                  elsif the_state == val
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return the_state, :keep
         
     | 
| 
       45 
47 
     | 
    
         
             
                  else 
         
     | 
| 
       46 
48 
     | 
    
         
             
                    return val, :replace
         
     | 
| 
       47 
49 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -86,41 +88,35 @@ module Bud 
     | 
|
| 
       86 
88 
     | 
    
         
             
              def choose(x)
         
     | 
| 
       87 
89 
     | 
    
         
             
                [Choose.new, x]
         
     | 
| 
       88 
90 
     | 
    
         
             
              end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
              class  
     | 
| 
       91 
     | 
    
         
            -
                 
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
                  the_state = {:cnt => 1, :vals => [x]}
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              class ChooseOneRand < ArgExemplary #:nodoc: all
         
     | 
| 
      
 93 
     | 
    
         
            +
                def init(x=nil) # Vitter's reservoir sampling, sample size = 1
         
     | 
| 
      
 94 
     | 
    
         
            +
                  the_state = {:cnt => 1, :val => x}
         
     | 
| 
       94 
95 
     | 
    
         
             
                end
         
     | 
| 
       95 
96 
     | 
    
         | 
| 
       96 
97 
     | 
    
         
             
                def trans(the_state, val)
         
     | 
| 
       97 
98 
     | 
    
         
             
                  the_state[:cnt] += 1
         
     | 
| 
       98 
     | 
    
         
            -
                   
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
                     
     | 
| 
      
 99 
     | 
    
         
            +
                  j = rand(the_state[:cnt])
         
     | 
| 
      
 100 
     | 
    
         
            +
                  if j < 1 # replace
         
     | 
| 
      
 101 
     | 
    
         
            +
                    old_val = the_state[:val]
         
     | 
| 
      
 102 
     | 
    
         
            +
                    the_state[:val] = val
         
     | 
| 
      
 103 
     | 
    
         
            +
                    return the_state, :replace
         
     | 
| 
       101 
104 
     | 
    
         
             
                  else
         
     | 
| 
       102 
     | 
    
         
            -
                     
     | 
| 
       103 
     | 
    
         
            -
                    if j < @@reservoir_size
         
     | 
| 
       104 
     | 
    
         
            -
                      old_tup = the_state[:vals][j]
         
     | 
| 
       105 
     | 
    
         
            -
                      the_state[:vals][j] = val 
         
     | 
| 
       106 
     | 
    
         
            -
                      return the_state, [:delete, old_tup]
         
     | 
| 
       107 
     | 
    
         
            -
                    else
         
     | 
| 
       108 
     | 
    
         
            -
                      return the_state, :keep
         
     | 
| 
       109 
     | 
    
         
            -
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
                    return the_state, :ignore
         
     | 
| 
       110 
106 
     | 
    
         
             
                  end
         
     | 
| 
       111 
107 
     | 
    
         
             
                end
         
     | 
| 
       112 
108 
     | 
    
         
             
                def tie(the_state, val)
         
     | 
| 
       113 
109 
     | 
    
         
             
                  true
         
     | 
| 
       114 
110 
     | 
    
         
             
                end
         
     | 
| 
       115 
111 
     | 
    
         
             
                def final(the_state)
         
     | 
| 
       116 
     | 
    
         
            -
                  the_state[: 
     | 
| 
      
 112 
     | 
    
         
            +
                  the_state[:val] # XXX rand(@@reservoir_size will always be 0, since @@reservoir_size is 1
         
     | 
| 
       117 
113 
     | 
    
         
             
                end
         
     | 
| 
       118 
114 
     | 
    
         
             
              end
         
     | 
| 
       119 
115 
     | 
    
         | 
| 
       120 
116 
     | 
    
         
             
              # exemplary aggregate method to be used in Bud::BudCollection.group.  
         
     | 
| 
       121 
117 
     | 
    
         
             
              # randomly chooses among x entries being aggregated.
         
     | 
| 
       122 
118 
     | 
    
         
             
              def choose_rand(x=nil)
         
     | 
| 
       123 
     | 
    
         
            -
                [ 
     | 
| 
      
 119 
     | 
    
         
            +
                [ChooseOneRand.new, x]
         
     | 
| 
       124 
120 
     | 
    
         
             
              end
         
     | 
| 
       125 
121 
     | 
    
         | 
| 
       126 
122 
     | 
    
         
             
              class Sum < Agg #:nodoc: all
         
     | 
    
        data/lib/bud/bud_meta.rb
    CHANGED
    
    | 
         @@ -1,66 +1,45 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'bud/rewrite'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'bud/state'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'parse_tree'
         
     | 
| 
       4 
2 
     | 
    
         
             
            require 'pp'
         
     | 
| 
       5 
3 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            class BudMeta #:nodoc: all
         
     | 
| 
       7 
     | 
    
         
            -
              attr_reader :depanalysis
         
     | 
| 
       8 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
            class BudMeta #:nodoc: all
         
     | 
| 
       9 
6 
     | 
    
         
             
              def initialize(bud_instance, declarations)
         
     | 
| 
       10 
7 
     | 
    
         
             
                @bud_instance = bud_instance
         
     | 
| 
       11 
8 
     | 
    
         
             
                @declarations = declarations
         
     | 
| 
      
 9 
     | 
    
         
            +
                @dependency_analysis = nil # the results of bud_meta are analyzed further using a helper bloom instance. See depanalysis())
         
     | 
| 
       12 
10 
     | 
    
         
             
              end
         
     | 
| 
       13 
11 
     | 
    
         | 
| 
       14 
12 
     | 
    
         
             
              def meta_rewrite
         
     | 
| 
       15 
     | 
    
         
            -
                shred_rules
         
     | 
| 
       16 
     | 
    
         
            -
                top_stratum = stratify
         
     | 
| 
       17 
     | 
    
         
            -
                stratum_map = binaryrel2map(@bud_instance.t_stratum)
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                rewritten_strata = Array.new(top_stratum + 2) { [] }
         
     | 
| 
       20 
     | 
    
         
            -
                no_attr_rewrite_strata = Array.new(top_stratum + 2) { [] }
         
     | 
| 
       21 
     | 
    
         
            -
                @bud_instance.t_rules.each do |d|
         
     | 
| 
       22 
     | 
    
         
            -
                  if d.op.to_s == '<='
         
     | 
| 
       23 
     | 
    
         
            -
                    # Deductive rules are assigned to strata based on the basic Datalog
         
     | 
| 
       24 
     | 
    
         
            -
                    # stratification algorithm
         
     | 
| 
       25 
     | 
    
         
            -
                    belongs_in = stratum_map[d.lhs]
         
     | 
| 
       26 
     | 
    
         
            -
                    belongs_in ||= 0
         
     | 
| 
       27 
     | 
    
         
            -
                    rewritten_strata[belongs_in] << d.src
         
     | 
| 
       28 
     | 
    
         
            -
                    no_attr_rewrite_strata[belongs_in] << d.orig_src
         
     | 
| 
       29 
     | 
    
         
            -
                  else
         
     | 
| 
       30 
     | 
    
         
            -
                    # All temporal rules are placed in the last stratum
         
     | 
| 
       31 
     | 
    
         
            -
                    rewritten_strata[top_stratum + 1] << d.src
         
     | 
| 
       32 
     | 
    
         
            -
                    no_attr_rewrite_strata[top_stratum + 1] << d.orig_src
         
     | 
| 
       33 
     | 
    
         
            -
                  end
         
     | 
| 
       34 
     | 
    
         
            -
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
                shred_rules # capture dependencies, rewrite rules
         
     | 
| 
       35 
14 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                 
     | 
| 
       37 
     | 
    
         
            -
                @bud_instance. 
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                3.times { @depanalysis.tick_internal }
         
     | 
| 
      
 15 
     | 
    
         
            +
                stratified_rules = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                if @bud_instance.toplevel == @bud_instance
         
     | 
| 
      
 17 
     | 
    
         
            +
                  nodes, stratum_map, top_stratum = stratify_preds
         
     | 
| 
       40 
18 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                  puts "Warning: underspecified dataflow: #{u.inspect}"
         
     | 
| 
       43 
     | 
    
         
            -
                  @bud_instance.t_underspecified << u
         
     | 
| 
       44 
     | 
    
         
            -
                end
         
     | 
| 
       45 
     | 
    
         
            -
                @depanalysis.source.each do |s|
         
     | 
| 
       46 
     | 
    
         
            -
                  @bud_instance.sources[s.first] = true
         
     | 
| 
       47 
     | 
    
         
            -
                end
         
     | 
| 
       48 
     | 
    
         
            -
                @depanalysis.sink.each do |s|
         
     | 
| 
       49 
     | 
    
         
            -
                  @bud_instance.sinks[s.first] = true
         
     | 
| 
       50 
     | 
    
         
            -
                end
         
     | 
| 
       51 
     | 
    
         
            -
                  
         
     | 
| 
       52 
     | 
    
         
            -
                dump_rewrite(no_attr_rewrite_strata) if @bud_instance.options[:dump_rewrite]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # stratum_map = {fully qualified pred  => stratum}
         
     | 
| 
       53 
20 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
               
     | 
| 
      
 21 
     | 
    
         
            +
                  #slot each rule into the stratum corresponding to its lhs pred (from stratum_map)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  stratified_rules = Array.new(top_stratum + 2) { [] }  # stratum -> [ rules ]
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @bud_instance.t_rules.each do |rule|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    if rule.op.to_s == '<='
         
     | 
| 
      
 25 
     | 
    
         
            +
                      # Deductive rules are assigned to strata based on the basic Datalog
         
     | 
| 
      
 26 
     | 
    
         
            +
                      # stratification algorithm
         
     | 
| 
      
 27 
     | 
    
         
            +
                      belongs_in = stratum_map[rule.lhs]
         
     | 
| 
      
 28 
     | 
    
         
            +
                      belongs_in ||= 0
         
     | 
| 
      
 29 
     | 
    
         
            +
                      stratified_rules[belongs_in] << rule
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      # All temporal rules are placed in the last stratum
         
     | 
| 
      
 32 
     | 
    
         
            +
                      stratified_rules[top_stratum + 1] << rule
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # stratified_rules[0] may be empty if none of the nodes at stratum 0 are on the lhs
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # stratified_rules[top_stratum+1] will be empty if there are no temporal rules.
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # Cleanup
         
     | 
| 
      
 38 
     | 
    
         
            +
                  stratified_rules = stratified_rules.reject{|r| r.empty?}
         
     | 
| 
      
 39 
     | 
    
         
            +
                  dump_rewrite(stratified_rules) if @bud_instance.options[:dump_rewrite]
         
     | 
| 
       56 
40 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
              def binaryrel2map(rel)
         
     | 
| 
       58 
     | 
    
         
            -
                map = {}
         
     | 
| 
       59 
     | 
    
         
            -
                rel.each do |s|
         
     | 
| 
       60 
     | 
    
         
            -
                  raise Bud::Error unless s.length == 2
         
     | 
| 
       61 
     | 
    
         
            -
                  map[s[0]] = s[1]
         
     | 
| 
       62 
41 
     | 
    
         
             
                end
         
     | 
| 
       63 
     | 
    
         
            -
                return  
     | 
| 
      
 42 
     | 
    
         
            +
                return stratified_rules
         
     | 
| 
       64 
43 
     | 
    
         
             
              end
         
     | 
| 
       65 
44 
     | 
    
         | 
| 
       66 
45 
     | 
    
         
             
              def shred_rules
         
     | 
| 
         @@ -87,11 +66,18 @@ class BudMeta #:nodoc: all 
     | 
|
| 
       87 
66 
     | 
    
         
             
              end
         
     | 
| 
       88 
67 
     | 
    
         | 
| 
       89 
68 
     | 
    
         
             
              def rewrite_rule_block(klass, block_name, seed)
         
     | 
| 
       90 
     | 
    
         
            -
                 
     | 
| 
       91 
     | 
    
         
            -
                return unless parse_tree.first
         
     | 
| 
      
 69 
     | 
    
         
            +
                return unless klass.respond_to? :__bloom_asts__
         
     | 
| 
       92 
70 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                pt =  
     | 
| 
      
 71 
     | 
    
         
            +
                pt = klass.__bloom_asts__[block_name]
         
     | 
| 
      
 72 
     | 
    
         
            +
                return if pt.nil?
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                pt = Marshal.load(Marshal.dump(pt)) #deep clone because RuleRewriter mucks up pt.
         
     | 
| 
       94 
75 
     | 
    
         
             
                pp pt if @bud_instance.options[:dump_ast]
         
     | 
| 
      
 76 
     | 
    
         
            +
                tmp_expander = TempExpander.new
         
     | 
| 
      
 77 
     | 
    
         
            +
                pt = tmp_expander.process(pt)
         
     | 
| 
      
 78 
     | 
    
         
            +
                tmp_expander.tmp_tables.each do |t|
         
     | 
| 
      
 79 
     | 
    
         
            +
                  @bud_instance.temp(t.to_sym)
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
       95 
81 
     | 
    
         | 
| 
       96 
82 
     | 
    
         
             
                rv = check_rule_ast(pt)
         
     | 
| 
       97 
83 
     | 
    
         
             
                unless rv.nil?
         
     | 
| 
         @@ -112,12 +98,30 @@ class BudMeta #:nodoc: all 
     | 
|
| 
       112 
98 
     | 
    
         
             
                  end
         
     | 
| 
       113 
99 
     | 
    
         
             
                  raise Bud::CompileError, "#{error_msg} in rule block \"#{block_name}\"#{src_msg}"
         
     | 
| 
       114 
100 
     | 
    
         
             
                end
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
101 
     | 
    
         
             
                rewriter = RuleRewriter.new(seed, @bud_instance)
         
     | 
| 
       117 
102 
     | 
    
         
             
                rewriter.process(pt)
         
     | 
| 
       118 
103 
     | 
    
         
             
                return rewriter
         
     | 
| 
       119 
104 
     | 
    
         
             
              end
         
     | 
| 
       120 
105 
     | 
    
         | 
| 
      
 106 
     | 
    
         
            +
              def get_qual_name(pt)
         
     | 
| 
      
 107 
     | 
    
         
            +
                # expect to see a parse tree corresponding to a dotted name
         
     | 
| 
      
 108 
     | 
    
         
            +
                #    a.b.c == s(:call, s1, :c, (:args))
         
     | 
| 
      
 109 
     | 
    
         
            +
                # where s1 == s(:call, s2, :b, (:args))
         
     | 
| 
      
 110 
     | 
    
         
            +
                # where s2 == s(:call, nil,:a, (:args))
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                tag, recv, name, args = pt
         
     | 
| 
      
 113 
     | 
    
         
            +
                return nil unless tag == :call or args.length == 1
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                if recv
         
     | 
| 
      
 116 
     | 
    
         
            +
                  qn = get_qual_name(recv)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  return nil if qn.nil? or qn.size == 0
         
     | 
| 
      
 118 
     | 
    
         
            +
                  qn = qn + "." + name.to_s
         
     | 
| 
      
 119 
     | 
    
         
            +
                else
         
     | 
| 
      
 120 
     | 
    
         
            +
                  qn = name.to_s
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
                qn
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
       121 
125 
     | 
    
         
             
              # Perform some basic sanity checks on the AST of a rule block. We expect a
         
     | 
| 
       122 
126 
     | 
    
         
             
              # rule block to consist of a :defn, a nested :scope, and then a sequence of
         
     | 
| 
       123 
127 
     | 
    
         
             
              # statements. Each statement is a :call node. Returns nil (no error found), a
         
     | 
| 
         @@ -147,10 +151,9 @@ class BudMeta #:nodoc: all 
     | 
|
| 
       147 
151 
     | 
    
         
             
                  tag, lhs, op, rhs = n
         
     | 
| 
       148 
152 
     | 
    
         | 
| 
       149 
153 
     | 
    
         
             
                  # Check that LHS references a named collection
         
     | 
| 
       150 
     | 
    
         
            -
                   
     | 
| 
       151 
     | 
    
         
            -
                  lhs_name  
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                    return [n, "collection does not exist: '#{lhs_name}'"]
         
     | 
| 
      
 154 
     | 
    
         
            +
                  lhs_name = get_qual_name(lhs)
         
     | 
| 
      
 155 
     | 
    
         
            +
                  unless lhs_name and @bud_instance.tables.has_key? lhs_name.to_sym
         
     | 
| 
      
 156 
     | 
    
         
            +
                    return [n, "Collection does not exist: '#{lhs_name}'"]
         
     | 
| 
       154 
157 
     | 
    
         
             
                  end
         
     | 
| 
       155 
158 
     | 
    
         | 
| 
       156 
159 
     | 
    
         
             
                  return [n, "illegal operator: '#{op}'"] unless [:<, :<=].include? op
         
     | 
| 
         @@ -176,36 +179,121 @@ class BudMeta #:nodoc: all 
     | 
|
| 
       176 
179 
     | 
    
         
             
                return nil # No errors found
         
     | 
| 
       177 
180 
     | 
    
         
             
              end
         
     | 
| 
       178 
181 
     | 
    
         | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
                @bud_instance. 
     | 
| 
       186 
     | 
    
         
            -
                 
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
       188 
     | 
    
         
            -
                   
     | 
| 
       189 
     | 
    
         
            -
                   
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
              Node = Struct.new :name, :status, :stratum, :edges, :in_lhs, :in_body, :in_cycle, :is_neg_head
         
     | 
| 
      
 184 
     | 
    
         
            +
              # Node.status is one of :init, :in_progress, :done
         
     | 
| 
      
 185 
     | 
    
         
            +
              Edge = Struct.new :to, :op, :neg, :temporal
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
              def stratify_preds
         
     | 
| 
      
 188 
     | 
    
         
            +
                bud = @bud_instance.toplevel
         
     | 
| 
      
 189 
     | 
    
         
            +
                nodes = {}
         
     | 
| 
      
 190 
     | 
    
         
            +
                bud.t_depends.each do |d|
         
     | 
| 
      
 191 
     | 
    
         
            +
                  #t_depends [:bud_instance, :rule_id, :lhs, :op, :body] => [:nm]
         
     | 
| 
      
 192 
     | 
    
         
            +
                  lhs = (nodes[d.lhs.to_s] ||= Node.new(d.lhs.to_s, :init, 0, [], true, false, false, false))
         
     | 
| 
      
 193 
     | 
    
         
            +
                  lhs.in_lhs = true
         
     | 
| 
      
 194 
     | 
    
         
            +
                  body = (nodes[d.body.to_s] ||= Node.new(d.body.to_s, :init, 0, [], false, true, false, false))
         
     | 
| 
      
 195 
     | 
    
         
            +
                  temporal = d.op != "<=" 
         
     | 
| 
      
 196 
     | 
    
         
            +
                  lhs.edges << Edge.new(body, d.op, d.nm, temporal)
         
     | 
| 
      
 197 
     | 
    
         
            +
                  body.in_body = true
         
     | 
| 
       190 
198 
     | 
    
         
             
                end
         
     | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
                 
     | 
| 
       193 
     | 
    
         
            -
                 
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
                 
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                nodes.values.each {|n| calc_stratum(n, false, false, [n.name])}
         
     | 
| 
      
 201 
     | 
    
         
            +
                # Normalize stratum numbers because they may not be 0-based or consecutive
         
     | 
| 
      
 202 
     | 
    
         
            +
                remap = {}
         
     | 
| 
      
 203 
     | 
    
         
            +
                # if the nodes stratum numbers are [2, 3, 2, 4], remap = {2 => 0, 3 => 1, 4 => 2} 
         
     | 
| 
      
 204 
     | 
    
         
            +
                nodes.values.map {|n| n.stratum}.uniq.sort.each_with_index{|num, i|
         
     | 
| 
      
 205 
     | 
    
         
            +
                  remap[num] = i
         
     | 
| 
      
 206 
     | 
    
         
            +
                }
         
     | 
| 
      
 207 
     | 
    
         
            +
                stratum_map = {}
         
     | 
| 
      
 208 
     | 
    
         
            +
                top_stratum = -1
         
     | 
| 
      
 209 
     | 
    
         
            +
                nodes.each_pair do |name, n|
         
     | 
| 
      
 210 
     | 
    
         
            +
                  n.stratum = remap[n.stratum]
         
     | 
| 
      
 211 
     | 
    
         
            +
                  stratum_map[n.name] = n.stratum
         
     | 
| 
      
 212 
     | 
    
         
            +
                  top_stratum = max(top_stratum, n.stratum)
         
     | 
| 
       197 
213 
     | 
    
         
             
                end
         
     | 
| 
      
 214 
     | 
    
         
            +
                analyze_dependencies(nodes)
         
     | 
| 
      
 215 
     | 
    
         
            +
                return nodes, stratum_map, top_stratum
         
     | 
| 
      
 216 
     | 
    
         
            +
              end
         
     | 
| 
       198 
217 
     | 
    
         | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
      
 218 
     | 
    
         
            +
              def max(a, b) ; a > b ? a : b ; end
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
              def calc_stratum(node, neg, temporal, path)
         
     | 
| 
      
 221 
     | 
    
         
            +
                if node.status == :in_process
         
     | 
| 
      
 222 
     | 
    
         
            +
                  node.in_cycle = true
         
     | 
| 
      
 223 
     | 
    
         
            +
                  if neg and !temporal and node.is_neg_head
         
     | 
| 
      
 224 
     | 
    
         
            +
                    raise Bud::CompileError, "unstratifiable program: #{path.uniq.join(',')}"
         
     | 
| 
      
 225 
     | 
    
         
            +
                  end
         
     | 
| 
      
 226 
     | 
    
         
            +
                elsif node.status == :init
         
     | 
| 
      
 227 
     | 
    
         
            +
                  node.status = :in_process
         
     | 
| 
      
 228 
     | 
    
         
            +
                  node.edges.each do |edge|
         
     | 
| 
      
 229 
     | 
    
         
            +
                    node.is_neg_head = edge.neg
         
     | 
| 
      
 230 
     | 
    
         
            +
                    next if edge.op != "<="
         
     | 
| 
      
 231 
     | 
    
         
            +
                    body_stratum = calc_stratum(edge.to, (neg or edge.neg), (edge.temporal or temporal), path + [edge.to.name])
         
     | 
| 
      
 232 
     | 
    
         
            +
                    node.is_neg_head = false #reset for next edge
         
     | 
| 
      
 233 
     | 
    
         
            +
                    node.stratum = max(node.stratum, body_stratum + (edge.neg ? 1 : 0))
         
     | 
| 
      
 234 
     | 
    
         
            +
                  end
         
     | 
| 
      
 235 
     | 
    
         
            +
                  node.status = :done
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
      
 237 
     | 
    
         
            +
                node.stratum
         
     | 
| 
      
 238 
     | 
    
         
            +
              end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
              def analyze_dependencies(nodes)  # nodes = {node name => node}
         
     | 
| 
      
 242 
     | 
    
         
            +
                bud = @bud_instance
         
     | 
| 
      
 243 
     | 
    
         
            +
                                                                  
         
     | 
| 
      
 244 
     | 
    
         
            +
                preds_in_lhs = nodes.inject(Set.new) {|preds, name_n| preds.add(name_n[0]) if name_n[1].in_lhs; preds}
         
     | 
| 
      
 245 
     | 
    
         
            +
                preds_in_body = nodes.inject(Set.new) {|preds, name_n| preds.add(name_n[0]) if name_n[1].in_body; preds}
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                bud.t_provides.each do |p|
         
     | 
| 
      
 248 
     | 
    
         
            +
                  pred, input = p.interface, p.input
         
     | 
| 
      
 249 
     | 
    
         
            +
                  if input
         
     | 
| 
      
 250 
     | 
    
         
            +
                    # an interface pred is a source if it is an input and it is not in any rule's lhs
         
     | 
| 
      
 251 
     | 
    
         
            +
                    #bud.sources << [pred] unless (preds_in_lhs.include? pred)
         
     | 
| 
      
 252 
     | 
    
         
            +
                    unless preds_in_body.include? pred.to_s
         
     | 
| 
      
 253 
     | 
    
         
            +
                      # input interface is underspecified if not used in any rule body
         
     | 
| 
      
 254 
     | 
    
         
            +
                      bud.t_underspecified << [pred, true] # true indicates input mode
         
     | 
| 
      
 255 
     | 
    
         
            +
                      puts "Warning: input interface #{pred} not used"
         
     | 
| 
      
 256 
     | 
    
         
            +
                    end
         
     | 
| 
      
 257 
     | 
    
         
            +
                  else
         
     | 
| 
      
 258 
     | 
    
         
            +
                    # an interface pred is a sink if it is not an input and it is not in any rule's body
         
     | 
| 
      
 259 
     | 
    
         
            +
                    #(if it is in the body, then it is an intermediate node feeding some lhs)
         
     | 
| 
      
 260 
     | 
    
         
            +
                    #bud.sinks << [pred] unless (preds_in_body.include? pred)
         
     | 
| 
      
 261 
     | 
    
         
            +
                    unless preds_in_lhs.include? pred.to_s
         
     | 
| 
      
 262 
     | 
    
         
            +
                      # output interface underspecified if not in any rule's lhs
         
     | 
| 
      
 263 
     | 
    
         
            +
                      bud.t_underspecified << [pred, false]  #false indicates output mode.
         
     | 
| 
      
 264 
     | 
    
         
            +
                      puts "Warning: output interface #{pred} not used"
         
     | 
| 
      
 265 
     | 
    
         
            +
                    end
         
     | 
| 
      
 266 
     | 
    
         
            +
                  end
         
     | 
| 
      
 267 
     | 
    
         
            +
                end
         
     | 
| 
      
 268 
     | 
    
         
            +
              end
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
              def depanalysis
         
     | 
| 
      
 271 
     | 
    
         
            +
                if @dependency_analysis.nil?
         
     | 
| 
      
 272 
     | 
    
         
            +
                  require 'bud/depanalysis'
         
     | 
| 
      
 273 
     | 
    
         
            +
                  da = ::DepAnalysis.new
         
     | 
| 
      
 274 
     | 
    
         
            +
                  da.providing <+ @bud_instance.tables[:t_provides].to_a
         
     | 
| 
      
 275 
     | 
    
         
            +
                  da.depends <+ @bud_instance.t_depends.map{|d| [d.lhs, d.op, d.body, d.nm]}
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                  #@bud_instance.tables[:t_provides].each {|t| da.providing <+ t}
         
     | 
| 
      
 278 
     | 
    
         
            +
                  #@bud_instance.tables[:t_depends].each {|t| da.depends_tc <+ t}
         
     | 
| 
      
 279 
     | 
    
         
            +
                  da.tick_internal
         
     | 
| 
      
 280 
     | 
    
         
            +
                  @dependency_analysis = da
         
     | 
| 
      
 281 
     | 
    
         
            +
                end
         
     | 
| 
      
 282 
     | 
    
         
            +
                @dependency_analysis
         
     | 
| 
       200 
283 
     | 
    
         
             
              end
         
     | 
| 
       201 
284 
     | 
    
         | 
| 
       202 
285 
     | 
    
         
             
              def dump_rewrite(strata)
         
     | 
| 
       203 
286 
     | 
    
         
             
                fout = File.new("#{@bud_instance.class}_rewritten.txt", "w")
         
     | 
| 
       204 
287 
     | 
    
         
             
                fout.puts "Declarations:"
         
     | 
| 
       205 
288 
     | 
    
         | 
| 
       206 
     | 
    
         
            -
                strata.each_with_index do | 
     | 
| 
       207 
     | 
    
         
            -
                   
     | 
| 
       208 
     | 
    
         
            -
                  fout. 
     | 
| 
      
 289 
     | 
    
         
            +
                strata.each_with_index do |rules, i|
         
     | 
| 
      
 290 
     | 
    
         
            +
                  fout.print "=================================\n"
         
     | 
| 
      
 291 
     | 
    
         
            +
                  fout.print "Stratum #{i}\n"
         
     | 
| 
      
 292 
     | 
    
         
            +
                  rules.each do |r|
         
     | 
| 
      
 293 
     | 
    
         
            +
                    fout.puts "#{r.bud_obj.class}##{r.bud_obj.object_id} #{r.rule_id}"
         
     | 
| 
      
 294 
     | 
    
         
            +
                    fout.puts "\tsrc:      #{r.src}"
         
     | 
| 
      
 295 
     | 
    
         
            +
                    fout.puts "\torig src: #{r.orig_src}"
         
     | 
| 
      
 296 
     | 
    
         
            +
                  end
         
     | 
| 
       209 
297 
     | 
    
         
             
                end
         
     | 
| 
       210 
298 
     | 
    
         
             
                fout.close
         
     | 
| 
       211 
299 
     | 
    
         
             
              end
         
     | 
    
        data/lib/bud/bust/bust.rb
    CHANGED
    
    | 
         @@ -68,23 +68,30 @@ module Bust 
     | 
|
| 
       68 
68 
     | 
    
         
             
                      if @request =~ /GET .* HTTP*/
         
     | 
| 
       69 
69 
     | 
    
         
             
                        puts "GET shouldn't have body" if @body
         
     | 
| 
       70 
70 
     | 
    
         
             
                        # select the appropriate elements from the table
         
     | 
| 
       71 
     | 
    
         
            -
                        desired_elements =  
     | 
| 
       72 
     | 
    
         
            -
                          uri_params.all? {|k, v| 
     | 
| 
      
 71 
     | 
    
         
            +
                        desired_elements = @bud.send(table_name.to_sym).find_all do |t|
         
     | 
| 
      
 72 
     | 
    
         
            +
                          uri_params.all? {|k, v|
         
     | 
| 
      
 73 
     | 
    
         
            +
                            (eval "t." + k.to_s) == v[0]
         
     | 
| 
      
 74 
     | 
    
         
            +
                          }
         
     | 
| 
       73 
75 
     | 
    
         
             
                        end
         
     | 
| 
       74 
76 
     | 
    
         
             
                        @session.print success
         
     | 
| 
      
 77 
     | 
    
         
            +
                        desired_elements = desired_elements .map{|elem|
         
     | 
| 
      
 78 
     | 
    
         
            +
                          elem.class <= Struct ? elem.to_a : elem
         
     | 
| 
      
 79 
     | 
    
         
            +
                        }
         
     | 
| 
       75 
80 
     | 
    
         
             
                        @session.print desired_elements.to_json
         
     | 
| 
       76 
81 
     | 
    
         
             
                      elsif @request =~ /POST .* HTTP*/
         
     | 
| 
       77 
82 
     | 
    
         
             
                        # instantiate a new tuple
         
     | 
| 
       78 
83 
     | 
    
         
             
                        tuple_to_insert = []
         
     | 
| 
       79 
84 
     | 
    
         
             
                        @body.each do |k, v|
         
     | 
| 
       80 
     | 
    
         
            -
                          index =  
     | 
| 
      
 85 
     | 
    
         
            +
                          index = @bud.send(table_name.to_sym).cols.find_index(k.to_sym)
         
     | 
| 
       81 
86 
     | 
    
         
             
                          for i in (tuple_to_insert.size..index)
         
     | 
| 
       82 
87 
     | 
    
         
             
                            tuple_to_insert << nil
         
     | 
| 
       83 
88 
     | 
    
         
             
                          end
         
     | 
| 
       84 
89 
     | 
    
         
             
                          tuple_to_insert[index] = v[0]
         
     | 
| 
       85 
90 
     | 
    
         
             
                        end
         
     | 
| 
       86 
91 
     | 
    
         
             
                        # actually insert the puppy
         
     | 
| 
       87 
     | 
    
         
            -
                        @bud.async_do { 
     | 
| 
      
 92 
     | 
    
         
            +
                        @bud.async_do {
         
     | 
| 
      
 93 
     | 
    
         
            +
                          @bud.send(table_name.to_sym) <+ [tuple_to_insert]
         
     | 
| 
      
 94 
     | 
    
         
            +
                        }
         
     | 
| 
       88 
95 
     | 
    
         
             
                        @session.print success
         
     | 
| 
       89 
96 
     | 
    
         
             
                      end
         
     | 
| 
       90 
97 
     | 
    
         
             
                    rescue Exception
         
     |