hydroponics 0.3.2 → 0.3.3

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/ChangeLog.markdown CHANGED
@@ -1,3 +1,8 @@
1
+ # hydroponics 0.3.3
2
+
3
+ * Generalized the routes, so new actions can be added without changing them
4
+ * Added an action, Foreign Dupe for duplicating rows in a table while incrementing a foreign key.
5
+
1
6
  # hydroponics 0.3.2
2
7
 
3
8
  * Fixed require statements so other machines can run the gem
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.3.3
data/app/actions/dupe.rb CHANGED
@@ -1,14 +1,17 @@
1
1
  module Hydroponics
2
2
  module Actions
3
- def dupe(table, target_count)
3
+ # Dupe
4
+ #
5
+ # Change the total rows of a table to target_count, either by duplicating
6
+ # the first row or deleting rows from the end.
7
+ def dupe(table, data)
4
8
  table = table.to_sym
5
-
6
- first_row = @db[table].first
7
- first_row.delete(:id)
8
-
9
9
  current_count = @db[table].count
10
+ target_count = data['count'] || current_count
10
11
 
11
12
  if target_count > current_count
13
+ first_row = @db[table].first
14
+ first_row.delete(:id)
12
15
  @db[table].multi_insert([first_row] * (target_count - current_count))
13
16
  elsif current_count > target_count
14
17
  cutoff_id = @db[table].map(:id)[target_count-1]
@@ -0,0 +1,37 @@
1
+ require 'active_support/inflector'
2
+ require 'active_support/core_ext'
3
+
4
+ module Hydroponics
5
+ module Actions
6
+ # Foreign Dupe
7
+ #
8
+ # Just like Dupe, except it pulls valid foreign keys from table foreign_table.
9
+ #
10
+ # It starts from the beginning and increments as it goes.
11
+ def foreign_dupe(table, data)
12
+ table = table.to_sym
13
+ data.stringify_keys!
14
+ foreign_table = data['foreign_table'].to_sym
15
+ foreign_key_col = data['foreign_key'] || (foreign_table.to_s.singularize + "_id")
16
+ foreign_key_col = foreign_key_col.to_sym
17
+
18
+ current_count = @db[table].count
19
+ target_count = data['count'] || current_count
20
+
21
+ if target_count > current_count
22
+ foreign_ids = @db[foreign_table].map(:id)
23
+ first_row = @db[table].first
24
+ first_row.delete(:id)
25
+ n = target_count - current_count
26
+ @db[table].multi_insert( (1..n).collect { |i|
27
+ first_row.merge( Hash[foreign_key_col, foreign_ids[i % foreign_ids.size]] )
28
+ } )
29
+ elsif current_count > target_count
30
+ cutoff_id = @db[table].map(:id)[target_count-1]
31
+ @db[table].filter("id > #{cutoff_id}").delete
32
+ end
33
+
34
+ @db[table].count.to_s
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,111 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
4
+
5
+ <head>
6
+ <link href="../vendor/jquery-ui-1.8.5.custom/css/smoothness/jquery-ui-1.8.5.custom.css" media="screen" rel="stylesheet" type="text/css" />
7
+ <script type="text/javascript" src="../vendor/jquery-ui-1.8.5.custom/js/jquery-1.4.2.min.js"></script>
8
+ <script type="text/javascript" src="../vendor/jquery-ui-1.8.5.custom/js/jquery-ui-1.8.5.custom.min.js"></script>
9
+ <script type="text/javascript">
10
+ $(function(){
11
+ $("#slider div").slider({
12
+ slide: function(event, ui) {
13
+ $("#sliderct").html("<i>" + ui.value + "</i>");
14
+ $("button").button("enable");
15
+ },
16
+ max: 25000,
17
+ value: <%= db[@table].count %>
18
+ });
19
+
20
+ $("button").button();
21
+ $("button").button("enable");
22
+ $("button").click(function(){
23
+ $("#slider div").slider("disable");
24
+ $("button").button("disable");
25
+ $(".loader").show();
26
+
27
+ var postData = {
28
+ count: $("#slider div").slider("value"),
29
+ foreign_table: "<%= params[:foreign_table] %>"
30
+ };
31
+ if($("#foreign_key").val() != "") {
32
+ postData.foreign_key = $("#foreign_key").val()
33
+ }
34
+
35
+ $.ajax({
36
+ type: "POST",
37
+ url: "/foreign_dupe/<%= @table %>",
38
+ data: JSON.stringify(postData),
39
+ success: function(data, status, xhr) {
40
+ $("#sliderct").html("<b>" + data + "</b>");
41
+ $("#slider div").slider("enable");
42
+ $(".loader").hide();
43
+ },
44
+ processData: false
45
+ });
46
+ });
47
+ });
48
+ </script>
49
+ <style type="text/css">
50
+ .container {width:950px;margin:0 auto;}
51
+ .dupe h3 {
52
+ margin: 10px 5px 10px 18px;
53
+ color: #444;
54
+ float: left;
55
+ }
56
+ .dupe #slider {
57
+ float: left;
58
+ width: 252px;
59
+ margin: 16px 12px;
60
+ }
61
+ .dupecontainer {
62
+ height: 130px;
63
+ width: 501px;
64
+ }
65
+ .dupe {
66
+ height: 106px;
67
+ width: 500px;
68
+ border: 1px #ddd solid;
69
+ }
70
+ .dupe #button {
71
+ float: right;
72
+ margin: 2px 12px;
73
+ }
74
+ .dupe p {
75
+ padding: 50px 18px;
76
+ font-size: 12px;
77
+ }
78
+ h1, h3, p {
79
+ font-family: Verdana,Arial,sans-serif
80
+ }
81
+ .loader {
82
+ background-image: url('../ajax-loader.gif');
83
+ width: 32px;
84
+ height: 16px;
85
+ margin-top:16px;
86
+ float: left;
87
+ }
88
+ .dupe input {
89
+ float: right;
90
+ margin-top: 12px;
91
+ }
92
+ </style>
93
+ <title>Hydroponics <%= settings.version %></title>
94
+ </head>
95
+
96
+ <body class="container">
97
+ <div class="header">
98
+ <h1>Hydroponics</h1>
99
+ </div>
100
+ <div class="dupecontainer">
101
+ <div class="dupe">
102
+ <h3>Foreign Dupe</h3>
103
+ <div id='slider'><div></div></div>
104
+ <div class="loader" style="display:none;"></div>
105
+ <div id='button'><button>Update</button></div>
106
+ <input id='foreign_key'></input>
107
+ <p><%= @table.to_s.gsub("_"," ") %>: <span id='sliderct'><%= db[@table].count %></span></p>
108
+ </div>
109
+ </div>
110
+ </body>
111
+ </html>
data/config/hydro_app.rb CHANGED
@@ -19,13 +19,17 @@ class HydroApp < Sinatra::Base
19
19
  set :public, File.join(File.dirname(__FILE__), "../static")
20
20
  set :version, File.read(File.join(File.dirname(__FILE__), "../VERSION")).chomp
21
21
 
22
- post '/dupe/:table' do |table|
22
+ # new actions can be used without any changes to the routes, as long as they follow
23
+ # the existing format.
24
+ # => ex: GET /dupe/users; POST /dupe/users {count: 10}
25
+ # => ex: GET /foreign_dupe/portfolios?foreign_table=users; POST /foreign_dupe/users {count: 100, foreign_table: 'users'}
26
+ post '/:action/:table' do |action, table|
23
27
  data = JSON.parse(request.body.read)
24
- dupe(table, data['count'])
28
+ send(action.to_sym, table, data)
25
29
  end
26
30
 
27
- get '/dupe/:table' do |table|
31
+ get '/:action/:table' do |action, table|
28
32
  @table = table.to_sym
29
- erb :"dupe/index"
33
+ erb :"#{action}/index"
30
34
  end
31
35
  end
data/hydroponics.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{hydroponics}
8
- s.version = "0.3.2"
8
+ s.version = "0.3.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tyler Boyd"]
12
- s.date = %q{2010-10-29}
12
+ s.date = %q{2010-11-03}
13
13
  s.default_executable = %q{hydro}
14
14
  s.description = %q{A user interface to seed or destroy large quantities of data in a Rails app.}
15
15
  s.email = %q{tboyd47@gmail.com}
@@ -28,7 +28,9 @@ Gem::Specification.new do |s|
28
28
  "Rakefile",
29
29
  "VERSION",
30
30
  "app/actions/dupe.rb",
31
+ "app/actions/foreigndupe.rb",
31
32
  "app/views/dupe/index.erb",
33
+ "app/views/foreign_dupe/index.erb",
32
34
  "bin/hydro",
33
35
  "config/hydro_app.rb",
34
36
  "hydroponics.gemspec",
@@ -31,7 +31,7 @@ describe "HydroApp" do
31
31
 
32
32
  it "should show the table's count" do
33
33
  get '/dupe/users'
34
- last_response.body.include?("Count: " + @db[:users].count.to_s).should be_true
34
+ last_response.body.include?("<span id='sliderct'>" + @db[:users].count.to_s).should be_true
35
35
  end
36
36
  end
37
37
 
@@ -42,9 +42,25 @@ describe "HydroApp" do
42
42
  @db[:users].count.should == 10
43
43
  end
44
44
 
45
- it "should return the time elapsed on success" do
45
+ it "should return the final count on success" do
46
46
  post '/dupe/users', {:count => 10}.to_json
47
- last_response.body.match(/s$/).should be_true
47
+ last_response.body.match("10").should be_true
48
+ end
49
+ end
50
+
51
+ describe "/foreigndupe/*" do
52
+ it "should open foreigndupe/index.erb" do
53
+ get '/foreign_dupe/portfolios'
54
+ last_response.should be_ok
55
+ end
56
+ end
57
+
58
+ describe "/foreign_dupe/*/*" do
59
+ it "should copy the first row n times" do
60
+ @db[:users].multi_insert([{:name => "ABC", :email => "123@example.com"}] * 10)
61
+ post '/foreign_dupe/portfolios', {:count => 10, :foreign_table => 'users'}.to_json
62
+ last_response.should be_ok
63
+ @db[:portfolios].count.should == 10
48
64
  end
49
65
  end
50
66
  end
@@ -61,27 +61,67 @@ describe "Hydroponics::Actions" do
61
61
 
62
62
  describe "#dupe" do
63
63
  it "should duplicate the first user until the desired count is reached" do
64
- dupe(:users, 10)
64
+ dupe(:users, {'count' => 10})
65
65
  @db[:users].count.should == 10
66
66
  end
67
67
 
68
68
  it "should delete users from the end until the desired count is reached" do
69
69
  @db[:users].multi_insert([{:name => "ABC", :email => "123@example.com"}] * 10)
70
70
  @db[:users].count.should == 11
71
- dupe(:users, 2)
71
+ dupe(:users, {'count' => 2})
72
72
  @db[:users].count.should == 2
73
73
  end
74
74
 
75
75
  it "should handle non-consecutive id numbers" do
76
76
  @db[:users].multi_insert([{:id => 6789, :name => "ABC", :email => "123@example.com"}, {:id => 6790, :name => "ABC", :email => "123@example.com"}])
77
- dupe(:users, 2)
77
+ dupe(:users, {'count' => 2})
78
78
  @db[:users].count.should == 2
79
79
  end
80
80
 
81
81
  it "should require the table name and count" do
82
82
  lambda { dupe }.should raise_error
83
83
  lambda { dupe(:users) }.should raise_error
84
- lambda { dupe(16) }.should raise_error
84
+ lambda { dupe({'count' => 16}) }.should raise_error
85
+ end
86
+ end
87
+
88
+ describe "#foreigndupe" do
89
+ it "should copy the first row n times" do
90
+ @db[:users].multi_insert([{:name => "ABC", :email => "123@example.com"}] * 10)
91
+ foreign_dupe('portfolios', {:count => 10, :foreign_table => 'users'})
92
+ @db[:portfolios].count.should == 10
93
+ end
94
+
95
+ it "should add the foreign key" do
96
+ @db[:users].multi_insert([{:name => "ABC", :email => "123@example.com"}] * 10)
97
+ foreign_dupe('portfolios', {:count => 10, :foreign_table => 'users'})
98
+ @db[:portfolios].map(:user_id)[9].should > 0
99
+ end
100
+
101
+ it "should return the table's count" do
102
+ @db[:users].multi_insert([{:name => "ABC", :email => "123@example.com"}] * 10)
103
+ foreign_dupe('portfolios', {:count => 10, :foreign_table => 'users'}).should == "10"
104
+ end
105
+
106
+ it "should allow a custom foreign key name" do
107
+ @db.drop_table :portfolios if @db.table_exists?(:portfolios)
108
+ @db.create_table :portfolios do
109
+ primary_key :id
110
+ Integer :custom_id
111
+ String :experience
112
+ String :education
113
+ end
114
+ @db[:portfolios].insert(:experience => "None", :education => "None", :custom_id => @db[:users].first[:id])
115
+
116
+ foreign_dupe('portfolios', {:count => 10, :foreign_table => 'users', :foreign_key => "custom_id"}).should == "10"
117
+ @db[:portfolios].map(:custom_id)[9].should > 0
118
+ end
119
+
120
+ it "should start from the beginning of the foreign table if it runs out of foreign keys" do
121
+ @db[:users].multi_insert([{:name => "ABC", :email => "123@example.com"}] * 9) # so there are 10 total.
122
+ foreign_dupe('portfolios', {:count => 11, :foreign_table => 'users'})
123
+ @db[:portfolios].map(:user_id)[1].should == @db[:users].map(:id)[1]
124
+ @db[:portfolios].map(:user_id)[10].should == @db[:users].map(:id)[0]
85
125
  end
86
126
  end
87
127
  end
data/spec/spec_helper.rb CHANGED
@@ -26,10 +26,18 @@ end
26
26
  def populate_test_db
27
27
  db = Hydroponics.db
28
28
  db.drop_table :users if db.table_exists?(:users)
29
+ db.drop_table :portfolios if db.table_exists?(:portfolios)
29
30
  db.create_table :users do
30
31
  primary_key :id
31
32
  String :name
32
33
  String :email
33
34
  end
35
+ db.create_table :portfolios do
36
+ primary_key :id
37
+ Integer :user_id
38
+ String :experience
39
+ String :education
40
+ end
34
41
  db[:users].insert(:name => "Acorn Hrefski", :email => "acorn@example.com")
42
+ db[:portfolios].insert(:experience => "None", :education => "None", :user_id => db[:users].first[:id])
35
43
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hydroponics
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 2
10
- version: 0.3.2
9
+ - 3
10
+ version: 0.3.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tyler Boyd
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-29 00:00:00 -04:00
18
+ date: 2010-11-03 00:00:00 -04:00
19
19
  default_executable: hydro
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -138,7 +138,9 @@ files:
138
138
  - Rakefile
139
139
  - VERSION
140
140
  - app/actions/dupe.rb
141
+ - app/actions/foreigndupe.rb
141
142
  - app/views/dupe/index.erb
143
+ - app/views/foreign_dupe/index.erb
142
144
  - bin/hydro
143
145
  - config/hydro_app.rb
144
146
  - hydroponics.gemspec