seamusabshere-gdocs_bootstrap 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Seamus Abshere
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,44 @@
1
+ = gdocs_bootstrap
2
+
3
+ <tt>
4
+ class FuelType
5
+ gdoc_bootstrap :url => 'http://spreadsheets.google.com/pub?key=p70r3FHguhimIdBKyVz3iPA&output=csv&gid=0'
6
+ end
7
+ </tt>
8
+
9
+ This lets you bootstrap your ActiveRecord models with Google Docs spreadsheets.
10
+
11
+ <tt>
12
+ >> FuelType.bootstrap!
13
+ => true
14
+ </tt>
15
+
16
+ == Spreadsheet structure
17
+
18
+ The first column is always the key.
19
+
20
+ All of the other columns will be included as attributes, based on the column headers.
21
+
22
+ <tt>
23
+ name emission_factor units
24
+ coal 5246.89 lbs/short ton
25
+ natural gas 1.25   pounds / therm (nat gas)
26
+ fuel oil 22.51 lbs/gallon
27
+ </tt>
28
+
29
+ would generate
30
+
31
+ <tt>
32
+ a = FuelType.find_or_create_by_name('coal')
33
+ a.update_attributes(:name => 'coal', :emission_factor => '5246.89', :units => 'lbs/short ton')
34
+
35
+ a = FuelType.find_or_create_by_name('natural gas')
36
+ a.update_attributes(:name => 'coal', :emission_factor => '1.25', :units => 'pounds / therm (nat gas)')
37
+
38
+ a = FuelType.find_or_create_by_name('fuel oil')
39
+ a.update_attributes(:name => 'coal', :emission_factor => '22.51', :units => 'lbs/gallon')
40
+ </tt>
41
+
42
+ == Copyright
43
+
44
+ Copyright (c) 2009 Seamus Abshere. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "gdocs_bootstrap"
8
+ gem.summary = %Q{TODO}
9
+ gem.email = "seamus@abshere.net"
10
+ gem.homepage = "http://github.com/seamusabshere/gdocs_bootstrap"
11
+ gem.authors = ["Seamus Abshere"]
12
+
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ Rake::TestTask.new(:test) do |test|
21
+ test.libs << 'lib' << 'test'
22
+ test.pattern = 'test/**/*_test.rb'
23
+ test.verbose = true
24
+ end
25
+
26
+ begin
27
+ require 'rcov/rcovtask'
28
+ Rcov::RcovTask.new do |test|
29
+ test.libs << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+ rescue LoadError
34
+ task :rcov do
35
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36
+ end
37
+ end
38
+
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ if File.exist?('VERSION.yml')
45
+ config = YAML.load(File.read('VERSION.yml'))
46
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
47
+ else
48
+ version = ""
49
+ end
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "gdocs_bootstrap #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
56
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
@@ -0,0 +1,92 @@
1
+ require 'rubygems'
2
+ require 'fastercsv'
3
+ require 'open-uri'
4
+ require 'active_support'
5
+
6
+ class GdocsBootstrap
7
+ attr_accessor :url, :target_class_name, :key_sprintf # set in options
8
+ attr_accessor :key_name, :headers, :dictionary, :width
9
+
10
+ def bootstrap!
11
+ load_dictionary unless dictionary_loaded?
12
+ dictionary.each do |k, v|
13
+ instance_of_target_class = target_class.send("find_or_create_by_#{key_name}", v[key_name])
14
+ instance_of_target_class.update_attributes(v.except(key_name))
15
+ end
16
+ true
17
+ end
18
+
19
+ private
20
+
21
+ def initialize(options = {})
22
+ @url = options[:url]
23
+ @target_class_name = options[:target_class_name]
24
+ @key_sprintf = options[:key_sprintf] || '%s'
25
+ end
26
+
27
+ def dictionary_loaded?
28
+ !dictionary.nil?
29
+ end
30
+
31
+ def load_dictionary
32
+ self.dictionary = {}
33
+ open(url) do |data|
34
+ FasterCSV.parse(data, :headers => :first_row) do |row|
35
+ self.width ||= row.fields.size
36
+ self.key_name ||= row.headers[0].to_sym
37
+ self.headers ||= row.headers
38
+ next if row.fields[0].blank?
39
+ key = interpret_key(row.fields[0])
40
+ dictionary[key] = interpret_columns(row.fields[0..width])
41
+ end
42
+ end
43
+ end
44
+
45
+ def interpret_key(k)
46
+ k = k.to_s.strip
47
+ k = k.to_i if /\%[0-9\.]*d/.match(key_sprintf)
48
+ key_sprintf % k
49
+ end
50
+
51
+ def interpret_columns(columns)
52
+ memo = {}
53
+ columns.each_with_index do |column, index|
54
+ # puts "memo.merge!(headers[#{index}].to_sym => column) as memo.merge!(#{headers[index].to_sym} => #{column})"
55
+ memo.merge!(headers[index].to_sym => column)
56
+ end
57
+ memo
58
+ end
59
+
60
+ def target_class
61
+ target_class_name.constantize
62
+ end
63
+ end
64
+
65
+ module ActiveRecord
66
+ module GdocsBootstrapExt
67
+ def self.included(klass)
68
+ klass.class_eval do
69
+ self.class_inheritable_accessor :gdocs_bootstraps
70
+ extend ClassMethods
71
+ end
72
+ end
73
+
74
+ module ClassMethods
75
+ def gdocs_bootstrap(options = {})
76
+ self.gdocs_bootstraps ||= []
77
+ options[:target_class_name] ||= self.class_name
78
+ gdocs_bootstraps << GdocsBootstrap.new(options)
79
+ end
80
+
81
+ def clear_bootstraps
82
+ self.gdocs_bootstraps = []
83
+ end
84
+
85
+ def bootstrap!
86
+ gdocs_bootstraps.each { |b| b.bootstrap! }
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ ActiveRecord::Base.send :include, ActiveRecord::GdocsBootstrapExt
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ class GdocsBootstrapExtTest < Test::Unit::TestCase
4
+ def setup
5
+ GdocsBootstrapTestHelper::Initializer.setup_database
6
+ end
7
+
8
+ def teardown
9
+ Scrum.clear_bootstraps
10
+ GdocsBootstrapTestHelper::Initializer.teardown_database
11
+ end
12
+
13
+ def test_should_mixin_methods
14
+ assert Scrum.respond_to?(:gdocs_bootstrap)
15
+ assert Scrum.respond_to?(:clear_bootstraps)
16
+ assert Scrum.respond_to?(:bootstrap!)
17
+ end
18
+
19
+ def test_should_set_target_class
20
+ GdocsBootstrap.expects(:new).with(:target_class_name => 'Scrum')
21
+ Scrum.gdocs_bootstrap
22
+ end
23
+
24
+ def test_should_set_url
25
+ GdocsBootstrap.expects(:new).with(:target_class_name => 'Scrum', :url => GOOGLE_DOC_URL)
26
+ Scrum.gdocs_bootstrap :url => GOOGLE_DOC_URL
27
+ end
28
+
29
+ def test_should_bootstrap
30
+ Scrum.gdocs_bootstrap :url => GOOGLE_DOC_URL
31
+ GdocsBootstrap.any_instance.expects(:bootstrap!)
32
+ Scrum.bootstrap!
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class GdocsBootstrapTest < Test::Unit::TestCase
4
+ def setup
5
+ GdocsBootstrapTestHelper::Initializer.setup_database
6
+ @bootstrap = GdocsBootstrap.new(:target_class_name => 'Scrum', :url => GOOGLE_DOC_URL)
7
+ end
8
+
9
+ def teardown
10
+ Scrum.clear_bootstraps
11
+ GdocsBootstrapTestHelper::Initializer.teardown_database
12
+ end
13
+
14
+ def test_should_have_url
15
+ assert_equal @bootstrap.url, GOOGLE_DOC_URL
16
+ end
17
+
18
+ def test_should_have_target_class_name
19
+ assert_equal @bootstrap.target_class_name, 'Scrum'
20
+ end
21
+
22
+ def test_should_bootstrap_keys
23
+ Scrum.expects(:find_or_create_by_name).at_least_once.returns(Scrum.new)
24
+ @bootstrap.bootstrap!
25
+ end
26
+
27
+ def test_should_bootstrap_values
28
+ Scrum.any_instance.expects(:update_attributes).at_least_once
29
+ @bootstrap.bootstrap!
30
+ end
31
+ end
@@ -0,0 +1,65 @@
1
+ module GdocsBootstrapTestHelper
2
+ module Initializer
3
+ VENDOR_RAILS = File.expand_path('../../../../rails', __FILE__)
4
+ OTHER_RAILS = File.expand_path('../../../rails', __FILE__)
5
+ PLUGIN_ROOT = File.expand_path('../../', __FILE__)
6
+
7
+ def self.rails_directory
8
+ if File.exist?(VENDOR_RAILS)
9
+ VENDOR_RAILS
10
+ elsif File.exist?(OTHER_RAILS)
11
+ OTHER_RAILS
12
+ end
13
+ end
14
+
15
+ def self.load_dependencies
16
+ if rails_directory
17
+ $:.unshift(File.join(rails_directory, 'activesupport', 'lib'))
18
+ $:.unshift(File.join(rails_directory, 'activerecord', 'lib'))
19
+ else
20
+ require 'rubygems' rescue LoadError
21
+ end
22
+
23
+ require 'active_record'
24
+ require 'test/unit'
25
+ require 'mocha'
26
+
27
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
28
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
29
+ require 'gdocs_bootstrap'
30
+ end
31
+
32
+ def self.configure_database
33
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
34
+ ActiveRecord::Migration.verbose = false
35
+ end
36
+
37
+ def self.setup_database
38
+ ActiveRecord::Schema.define do
39
+ create_table :scrums do |t|
40
+ t.string :name
41
+ t.string :emission_factor
42
+ t.string :units
43
+ t.timestamps
44
+ end
45
+ end
46
+ end
47
+
48
+ def self.teardown_database
49
+ ActiveRecord::Base.connection.tables.each do |table|
50
+ ActiveRecord::Base.connection.drop_table(table)
51
+ end
52
+ end
53
+
54
+ def self.start
55
+ load_dependencies
56
+ configure_database
57
+ end
58
+ end
59
+ end
60
+
61
+ GdocsBootstrapTestHelper::Initializer.start
62
+
63
+ class Scrum < ActiveRecord::Base; end
64
+
65
+ GOOGLE_DOC_URL = 'http://spreadsheets.google.com/pub?key=p70r3FHguhimIdBKyVz3iPA&output=csv&gid=0'
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seamusabshere-gdocs_bootstrap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Seamus Abshere
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-07 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: seamus@abshere.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - LICENSE
27
+ - README.rdoc
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - lib/gdocs_bootstrap.rb
31
+ - test/gdocs_bootstrap_ext_test.rb
32
+ - test/gdocs_bootstrap_test.rb
33
+ - test/test_helper.rb
34
+ has_rdoc: true
35
+ homepage: http://github.com/seamusabshere/gdocs_bootstrap
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --charset=UTF-8
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.2.0
57
+ signing_key:
58
+ specification_version: 2
59
+ summary: TODO
60
+ test_files:
61
+ - test/gdocs_bootstrap_ext_test.rb
62
+ - test/gdocs_bootstrap_test.rb
63
+ - test/test_helper.rb