hydroponics 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.markdown +5 -0
- data/VERSION +1 -1
- data/app/actions/dupe.rb +8 -5
- data/app/actions/foreigndupe.rb +37 -0
- data/app/views/foreign_dupe/index.erb +111 -0
- data/config/hydro_app.rb +8 -4
- data/hydroponics.gemspec +4 -2
- data/spec/hydro_app_spec.rb +19 -3
- data/spec/hydroponics_spec.rb +44 -4
- data/spec/spec_helper.rb +8 -0
- metadata +6 -4
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.
|
1
|
+
0.3.3
|
data/app/actions/dupe.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
module Hydroponics
|
2
2
|
module Actions
|
3
|
-
|
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
|
-
|
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
|
-
|
28
|
+
send(action.to_sym, table, data)
|
25
29
|
end
|
26
30
|
|
27
|
-
get '
|
31
|
+
get '/:action/:table' do |action, table|
|
28
32
|
@table = table.to_sym
|
29
|
-
erb :"
|
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.
|
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-
|
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",
|
data/spec/hydro_app_spec.rb
CHANGED
@@ -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?("
|
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
|
45
|
+
it "should return the final count on success" do
|
46
46
|
post '/dupe/users', {:count => 10}.to_json
|
47
|
-
last_response.body.match(
|
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
|
data/spec/hydroponics_spec.rb
CHANGED
@@ -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:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
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-
|
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
|