activerecord-import 1.0.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.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +32 -0
  3. data/.rubocop.yml +49 -0
  4. data/.rubocop_todo.yml +36 -0
  5. data/.travis.yml +74 -0
  6. data/Brewfile +3 -0
  7. data/CHANGELOG.md +430 -0
  8. data/Gemfile +59 -0
  9. data/LICENSE +56 -0
  10. data/README.markdown +619 -0
  11. data/Rakefile +68 -0
  12. data/activerecord-import.gemspec +23 -0
  13. data/benchmarks/README +32 -0
  14. data/benchmarks/benchmark.rb +68 -0
  15. data/benchmarks/lib/base.rb +138 -0
  16. data/benchmarks/lib/cli_parser.rb +107 -0
  17. data/benchmarks/lib/float.rb +15 -0
  18. data/benchmarks/lib/mysql2_benchmark.rb +19 -0
  19. data/benchmarks/lib/output_to_csv.rb +19 -0
  20. data/benchmarks/lib/output_to_html.rb +64 -0
  21. data/benchmarks/models/test_innodb.rb +3 -0
  22. data/benchmarks/models/test_memory.rb +3 -0
  23. data/benchmarks/models/test_myisam.rb +3 -0
  24. data/benchmarks/schema/mysql_schema.rb +16 -0
  25. data/gemfiles/3.2.gemfile +2 -0
  26. data/gemfiles/4.0.gemfile +2 -0
  27. data/gemfiles/4.1.gemfile +2 -0
  28. data/gemfiles/4.2.gemfile +2 -0
  29. data/gemfiles/5.0.gemfile +2 -0
  30. data/gemfiles/5.1.gemfile +2 -0
  31. data/gemfiles/5.2.gemfile +2 -0
  32. data/gemfiles/6.0.gemfile +1 -0
  33. data/gemfiles/6.1.gemfile +1 -0
  34. data/lib/activerecord-import.rb +6 -0
  35. data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +9 -0
  36. data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +6 -0
  37. data/lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb +6 -0
  38. data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +6 -0
  39. data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +6 -0
  40. data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +6 -0
  41. data/lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb +7 -0
  42. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +6 -0
  43. data/lib/activerecord-import/adapters/abstract_adapter.rb +66 -0
  44. data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +5 -0
  45. data/lib/activerecord-import/adapters/mysql2_adapter.rb +5 -0
  46. data/lib/activerecord-import/adapters/mysql_adapter.rb +129 -0
  47. data/lib/activerecord-import/adapters/postgresql_adapter.rb +217 -0
  48. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +180 -0
  49. data/lib/activerecord-import/base.rb +43 -0
  50. data/lib/activerecord-import/import.rb +1059 -0
  51. data/lib/activerecord-import/mysql2.rb +7 -0
  52. data/lib/activerecord-import/postgresql.rb +7 -0
  53. data/lib/activerecord-import/sqlite3.rb +7 -0
  54. data/lib/activerecord-import/synchronize.rb +66 -0
  55. data/lib/activerecord-import/value_sets_parser.rb +77 -0
  56. data/lib/activerecord-import/version.rb +5 -0
  57. data/test/adapters/jdbcmysql.rb +1 -0
  58. data/test/adapters/jdbcpostgresql.rb +1 -0
  59. data/test/adapters/jdbcsqlite3.rb +1 -0
  60. data/test/adapters/makara_postgis.rb +1 -0
  61. data/test/adapters/mysql2.rb +1 -0
  62. data/test/adapters/mysql2_makara.rb +1 -0
  63. data/test/adapters/mysql2spatial.rb +1 -0
  64. data/test/adapters/postgis.rb +1 -0
  65. data/test/adapters/postgresql.rb +1 -0
  66. data/test/adapters/postgresql_makara.rb +1 -0
  67. data/test/adapters/seamless_database_pool.rb +1 -0
  68. data/test/adapters/spatialite.rb +1 -0
  69. data/test/adapters/sqlite3.rb +1 -0
  70. data/test/database.yml.sample +52 -0
  71. data/test/import_test.rb +903 -0
  72. data/test/jdbcmysql/import_test.rb +5 -0
  73. data/test/jdbcpostgresql/import_test.rb +4 -0
  74. data/test/jdbcsqlite3/import_test.rb +4 -0
  75. data/test/makara_postgis/import_test.rb +8 -0
  76. data/test/models/account.rb +3 -0
  77. data/test/models/alarm.rb +2 -0
  78. data/test/models/bike_maker.rb +7 -0
  79. data/test/models/book.rb +9 -0
  80. data/test/models/car.rb +3 -0
  81. data/test/models/chapter.rb +4 -0
  82. data/test/models/dictionary.rb +4 -0
  83. data/test/models/discount.rb +3 -0
  84. data/test/models/end_note.rb +4 -0
  85. data/test/models/group.rb +3 -0
  86. data/test/models/promotion.rb +3 -0
  87. data/test/models/question.rb +3 -0
  88. data/test/models/rule.rb +3 -0
  89. data/test/models/tag.rb +4 -0
  90. data/test/models/topic.rb +23 -0
  91. data/test/models/user.rb +3 -0
  92. data/test/models/user_token.rb +4 -0
  93. data/test/models/vendor.rb +7 -0
  94. data/test/models/widget.rb +24 -0
  95. data/test/mysql2/import_test.rb +5 -0
  96. data/test/mysql2_makara/import_test.rb +6 -0
  97. data/test/mysqlspatial2/import_test.rb +6 -0
  98. data/test/postgis/import_test.rb +8 -0
  99. data/test/postgresql/import_test.rb +4 -0
  100. data/test/schema/generic_schema.rb +194 -0
  101. data/test/schema/jdbcpostgresql_schema.rb +1 -0
  102. data/test/schema/mysql2_schema.rb +19 -0
  103. data/test/schema/postgis_schema.rb +1 -0
  104. data/test/schema/postgresql_schema.rb +47 -0
  105. data/test/schema/sqlite3_schema.rb +13 -0
  106. data/test/schema/version.rb +10 -0
  107. data/test/sqlite3/import_test.rb +4 -0
  108. data/test/support/active_support/test_case_extensions.rb +75 -0
  109. data/test/support/assertions.rb +73 -0
  110. data/test/support/factories.rb +64 -0
  111. data/test/support/generate.rb +29 -0
  112. data/test/support/mysql/import_examples.rb +98 -0
  113. data/test/support/postgresql/import_examples.rb +563 -0
  114. data/test/support/shared_examples/on_duplicate_key_ignore.rb +43 -0
  115. data/test/support/shared_examples/on_duplicate_key_update.rb +368 -0
  116. data/test/support/shared_examples/recursive_import.rb +216 -0
  117. data/test/support/sqlite3/import_examples.rb +231 -0
  118. data/test/synchronize_test.rb +41 -0
  119. data/test/test_helper.rb +75 -0
  120. data/test/travis/database.yml +66 -0
  121. data/test/value_sets_bytes_parser_test.rb +104 -0
  122. data/test/value_sets_records_parser_test.rb +32 -0
  123. metadata +259 -0
@@ -0,0 +1,68 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+
7
+ namespace :display do
8
+ task :notice do
9
+ puts
10
+ puts "To run tests you must supply the adapter, see rake -T for more information."
11
+ puts
12
+ end
13
+ end
14
+ task default: ["display:notice"]
15
+
16
+ ADAPTERS = %w(
17
+ mysql2
18
+ mysql2_makara
19
+ mysql2spatial
20
+ jdbcmysql
21
+ jdbcsqlite3
22
+ jdbcpostgresql
23
+ postgresql
24
+ postgresql_makara
25
+ postgis
26
+ makara_postgis
27
+ sqlite3
28
+ spatialite
29
+ seamless_database_pool
30
+ ).freeze
31
+ ADAPTERS.each do |adapter|
32
+ namespace :test do
33
+ desc "Runs #{adapter} database tests."
34
+ Rake::TestTask.new(adapter) do |t|
35
+ # FactoryBot has an issue with warnings, so turn off, so noisy
36
+ # t.warning = true
37
+ t.test_files = FileList["test/adapters/#{adapter}.rb", "test/*_test.rb", "test/active_record/*_test.rb", "test/#{adapter}/**/*_test.rb"]
38
+ end
39
+ task adapter
40
+ end
41
+ end
42
+
43
+ begin
44
+ require 'rcov/rcovtask'
45
+ adapter = ENV['ARE_DB']
46
+ Rcov::RcovTask.new do |test|
47
+ test.libs << 'test'
48
+ test.pattern = ["test/adapters/#{adapter}.rb", "test/*_test.rb", "test/#{adapter}/**/*_test.rb"]
49
+ test.verbose = true
50
+ end
51
+ rescue LoadError
52
+ task :rcov do
53
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
54
+ end
55
+ end
56
+
57
+ require 'rdoc/task'
58
+ Rake::RDocTask.new do |rdoc|
59
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
60
+
61
+ rdoc.rdoc_dir = 'rdoc'
62
+ rdoc.title = "activerecord-import #{version}"
63
+ rdoc.rdoc_files.include('README*')
64
+ rdoc.rdoc_files.include('lib/**/*.rb')
65
+ end
66
+
67
+ require 'rubocop/rake_task'
68
+ RuboCop::RakeTask.new
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/activerecord-import/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Zach Dennis"]
6
+ gem.email = ["zach.dennis@gmail.com"]
7
+ gem.summary = "Bulk insert extension for ActiveRecord"
8
+ gem.description = "A library for bulk inserting data using ActiveRecord."
9
+ gem.homepage = "http://github.com/zdennis/activerecord-import"
10
+ gem.license = "Ruby"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "activerecord-import"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = ActiveRecord::Import::VERSION
18
+
19
+ gem.required_ruby_version = ">= 1.9.2"
20
+
21
+ gem.add_runtime_dependency "activerecord", ">= 3.2"
22
+ gem.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,32 @@
1
+ To run the benchmarks, from within the benchmarks run:
2
+ ruby benchmark.rb [options]
3
+
4
+ The following options are supported:
5
+ --adapter [String] The database adapter to use. IE: mysql, postgresql, oracle
6
+
7
+ --do-not-delete By default all records in the benchmark tables will be deleted at the end of the benchmark. This flag indicates not to delete the benchmark data.
8
+ --num [Integer] The number of objects to benchmark. (Required!)
9
+ --table-type [String] The table type to test. This can be used multiple times. By default it is all table types.
10
+ --to-csv [String] Print results in a CSV file format
11
+ --to-html [String] Print results in HTML format (String filename must be supplied)
12
+
13
+ See "ruby benchmark.rb -h" for the complete listing of options.
14
+
15
+ EXAMPLES
16
+ --------
17
+ To output to html format:
18
+ ruby benchmark.rb --adapter=mysql2 --to-html=results.html
19
+
20
+ To output to csv format:
21
+ ruby benchmark.rb --adapter=mysql2 --to-csv=results.csv
22
+
23
+ LIMITATIONS
24
+ -----------
25
+ Currently MySQL is the only supported adapter to benchmark.
26
+
27
+ AUTHOR
28
+ ------
29
+ Zach Dennis
30
+ zach.dennis@gmail.com
31
+ http://www.continuousthinking.com
32
+
@@ -0,0 +1,68 @@
1
+ require 'pathname'
2
+ require "fileutils"
3
+ require "active_record"
4
+ require "active_record/base"
5
+
6
+ benchmark_dir = File.dirname(__FILE__)
7
+
8
+ $LOAD_PATH.unshift('.')
9
+
10
+ # Get the gem into the load path
11
+ $LOAD_PATH.unshift(File.join(benchmark_dir, '..', 'lib'))
12
+
13
+ # Load the benchmark files
14
+ Dir[File.join( benchmark_dir, 'lib', '*.rb' )].sort.each { |f| require f }
15
+
16
+ # Parse the options passed in via the command line
17
+ options = BenchmarkOptionParser.parse( ARGV )
18
+
19
+ FileUtils.mkdir_p 'log'
20
+ ActiveRecord::Base.configurations["test"] = YAML.load_file(File.join(benchmark_dir, "../test/database.yml"))[options.adapter]
21
+ ActiveRecord::Base.logger = Logger.new("log/test.log")
22
+ ActiveRecord::Base.logger.level = Logger::DEBUG
23
+ ActiveRecord::Base.default_timezone = :utc
24
+
25
+ require "activerecord-import"
26
+ ActiveRecord::Base.establish_connection(:test)
27
+
28
+ ActiveSupport::Notifications.subscribe(/active_record.sql/) do |_, _, _, _, hsh|
29
+ ActiveRecord::Base.logger.info hsh[:sql]
30
+ end
31
+
32
+ # Load base/generic schema
33
+ require File.join(benchmark_dir, "../test/schema/version")
34
+ require File.join(benchmark_dir, "../test/schema/generic_schema")
35
+ adapter_schema = File.join(benchmark_dir, "schema/#{options.adapter}_schema.rb")
36
+ require adapter_schema if File.exist?(adapter_schema)
37
+
38
+ Dir[File.dirname(__FILE__) + "/models/*.rb"].each { |file| require file }
39
+
40
+ require File.join( benchmark_dir, 'lib', "#{options.adapter}_benchmark" )
41
+
42
+ table_types = nil
43
+ table_types = if options.benchmark_all_types
44
+ ["all"]
45
+ else
46
+ options.table_types.keys
47
+ end
48
+
49
+ letter = options.adapter[0].chr
50
+ clazz_str = letter.upcase + options.adapter[1..-1].downcase
51
+ clazz = Object.const_get( clazz_str + "Benchmark" )
52
+
53
+ benchmarks = []
54
+ options.number_of_objects.each do |num|
55
+ benchmarks << (benchmark = clazz.new)
56
+ benchmark.send( "benchmark", table_types, num )
57
+ end
58
+
59
+ options.outputs.each do |output|
60
+ format = output.format.downcase
61
+ output_module = Object.const_get( "OutputTo#{format.upcase}" )
62
+ benchmarks.each do |benchmark|
63
+ output_module.output_results( output.filename, benchmark.results )
64
+ end
65
+ end
66
+
67
+ puts
68
+ puts "Done with benchmark!"
@@ -0,0 +1,138 @@
1
+ class BenchmarkBase
2
+ attr_reader :results
3
+
4
+ # The main benchmark method dispatcher. This dispatches the benchmarks
5
+ # to actual benchmark_xxxx methods.
6
+ #
7
+ # == PARAMETERS
8
+ # * table_types - an array of table types to benchmark
9
+ # * num - the number of record insertions to test
10
+ def benchmark( table_types, num )
11
+ array_of_cols_and_vals = build_array_of_cols_and_vals( num )
12
+ table_types.each do |table_type|
13
+ send( "benchmark_#{table_type}", array_of_cols_and_vals )
14
+ end
15
+ end
16
+
17
+ # Returns an OpenStruct which contains two attritues, +description+ and +tms+ after performing an
18
+ # actual benchmark.
19
+ #
20
+ # == PARAMETERS
21
+ # * description - the description of the block that is getting benchmarked
22
+ # * blk - the block of code to benchmark
23
+ #
24
+ # == RETURNS
25
+ # An OpenStruct object with the following attributes:
26
+ # * description - the description of the benchmark ran
27
+ # * tms - a Benchmark::Tms containing the results of the benchmark
28
+ def bm( description )
29
+ tms = nil
30
+ puts "Benchmarking #{description}"
31
+
32
+ Benchmark.bm { |x| tms = x.report { yield } }
33
+ delete_all
34
+ failed = false
35
+
36
+ OpenStruct.new description: description, tms: tms, failed: failed
37
+ end
38
+
39
+ # Given a model class (ie: Topic), and an array of columns and value sets
40
+ # this will perform all of the benchmarks necessary for this library.
41
+ #
42
+ # == PARAMETERS
43
+ # * model_clazz - the model class to benchmark (ie: Topic)
44
+ # * array_of_cols_and_vals - an array of column identifiers and value sets
45
+ #
46
+ # == RETURNS
47
+ # returns true
48
+ def bm_model( model_clazz, array_of_cols_and_vals )
49
+ puts
50
+ puts "------ Benchmarking #{model_clazz.name} -------"
51
+
52
+ cols, vals = array_of_cols_and_vals
53
+ num_inserts = vals.size
54
+
55
+ # add a new result group for this particular benchmark
56
+ group = []
57
+ @results << group
58
+
59
+ description = "#{model_clazz.name}.create (#{num_inserts} records)"
60
+ group << bm( description ) do
61
+ vals.each do |values|
62
+ model_clazz.create create_hash_for_cols_and_vals( cols, values )
63
+ end
64
+ end
65
+
66
+ description = "#{model_clazz.name}.import(column, values) for #{num_inserts} records with validations"
67
+ group << bm( description ) { model_clazz.import cols, vals, validate: true }
68
+
69
+ description = "#{model_clazz.name}.import(columns, values) for #{num_inserts} records without validations"
70
+ group << bm( description ) { model_clazz.import cols, vals, validate: false }
71
+
72
+ models = []
73
+ array_of_attrs = []
74
+
75
+ vals.each do |arr|
76
+ array_of_attrs << (attrs = {})
77
+ arr.each_with_index { |value, i| attrs[cols[i]] = value }
78
+ end
79
+ array_of_attrs.each { |attrs| models << model_clazz.new(attrs) }
80
+
81
+ description = "#{model_clazz.name}.import(models) for #{num_inserts} records with validations"
82
+ group << bm( description ) { model_clazz.import models, validate: true }
83
+
84
+ description = "#{model_clazz.name}.import(models) for #{num_inserts} records without validations"
85
+ group << bm( description ) { model_clazz.import models, validate: false }
86
+
87
+ true
88
+ end
89
+
90
+ # Returns a two element array composing of an array of columns and an array of
91
+ # value sets given the passed +num+.
92
+ #
93
+ # === What is a value set?
94
+ # A value set is an array of arrays. Each child array represents an array of value sets
95
+ # for a given row of data.
96
+ #
97
+ # For example, say we wanted to represent an insertion of two records:
98
+ # column_names = [ 'id', 'name', 'description' ]
99
+ # record1 = [ 1, 'John Doe', 'A plumber' ]
100
+ # record2 = [ 2, 'John Smith', 'A painter' ]
101
+ # value_set [ record1, record2 ]
102
+ #
103
+ # == PARAMETER
104
+ # * num - the number of records to create
105
+ def build_array_of_cols_and_vals( num )
106
+ cols = [:my_name, :description]
107
+ value_sets = []
108
+ num.times { |i| value_sets << ["My Name #{i}", "My Description #{i}"] }
109
+ [cols, value_sets]
110
+ end
111
+
112
+ # Returns a hash of column identifier to value mappings giving the passed in
113
+ # value array.
114
+ #
115
+ # Example:
116
+ # cols = [ 'id', 'name', 'description' ]
117
+ # values = [ 1, 'John Doe', 'A plumber' ]
118
+ # hsh = create_hash_for_cols_and_vals( cols, values )
119
+ # # hsh => { 'id'=>1, 'name'=>'John Doe', 'description'=>'A plumber' }
120
+ def create_hash_for_cols_and_vals( cols, vals )
121
+ h = {}
122
+ cols.zip( vals ) { |col, val| h[col] = val }
123
+ h
124
+ end
125
+
126
+ # Deletes all records from all ActiveRecord subclasses
127
+ def delete_all
128
+ ActiveRecord::Base.send( :subclasses ).each do |subclass|
129
+ if subclass.table_exists? && subclass.respond_to?(:delete_all)
130
+ subclass.delete_all
131
+ end
132
+ end
133
+ end
134
+
135
+ def initialize # :nodoc:
136
+ @results = []
137
+ end
138
+ end
@@ -0,0 +1,107 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ #
5
+ # == PARAMETERS
6
+ # * a - database adapter. ie: mysql, postgresql, oracle, etc.
7
+ # * n - number of objects to test with. ie: 1, 100, 1000, etc.
8
+ # * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
9
+ #
10
+ module BenchmarkOptionParser
11
+ BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options.".freeze
12
+
13
+ def self.print_banner
14
+ puts BANNER
15
+ end
16
+
17
+ def self.print_banner!
18
+ print_banner
19
+ exit
20
+ end
21
+
22
+ def self.print_options( options )
23
+ puts "Benchmarking the following options:"
24
+ puts " Database adapter: #{options.adapter}"
25
+ puts " Number of objects: #{options.number_of_objects}"
26
+ puts " Table types:"
27
+ print_valid_table_types( options, prefix: " " )
28
+ end
29
+
30
+ # TODO IMPLEMENT THIS
31
+ def self.print_valid_table_types( options, hsh = { prefix: '' } )
32
+ if !options.table_types.keys.empty?
33
+ options.table_types.keys.sort.each { |type| puts hsh[:prefix].to_s + type.to_s }
34
+ else
35
+ puts 'No table types defined.'
36
+ end
37
+ end
38
+
39
+ def self.parse( args )
40
+ options = OpenStruct.new(
41
+ adapter: 'mysql2',
42
+ table_types: {},
43
+ delete_on_finish: true,
44
+ number_of_objects: [],
45
+ outputs: []
46
+ )
47
+
48
+ opt_parser = OptionParser.new do |opts|
49
+ opts.banner = BANNER
50
+
51
+ # parse the database adapter
52
+ opts.on( "a", "--adapter [String]",
53
+ "The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
54
+ options.adapter = arg
55
+ end
56
+
57
+ # parse do_not_delete flag
58
+ opts.on( "d", "--do-not-delete",
59
+ "By default all records in the benchmark tables will be deleted at the end of the benchmark. " \
60
+ "This flag indicates not to delete the benchmark data." ) do |_|
61
+ options.delete_on_finish = false
62
+ end
63
+
64
+ # parse the number of row objects to test
65
+ opts.on( "n", "--num [Integer]",
66
+ "The number of objects to benchmark." ) do |arg|
67
+ options.number_of_objects << arg.to_i
68
+ end
69
+
70
+ # parse the table types to test
71
+ opts.on( "t", "--table-type [String]",
72
+ "The table type to test. This can be used multiple times." ) do |arg|
73
+ if arg =~ /^all$/
74
+ options.table_types['all'] = options.benchmark_all_types = true
75
+ else
76
+ options.table_types[arg] = true
77
+ end
78
+ end
79
+
80
+ # print results in CSV format
81
+ opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
82
+ options.outputs << OpenStruct.new( format: 'csv', filename: filename)
83
+ end
84
+
85
+ # print results in HTML format
86
+ opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
87
+ options.outputs << OpenStruct.new( format: 'html', filename: filename )
88
+ end
89
+ end # end opt.parse!
90
+
91
+ begin
92
+ opt_parser.parse!( args )
93
+ if options.table_types.empty?
94
+ options.table_types['all'] = options.benchmark_all_types = true
95
+ end
96
+ rescue Exception
97
+ print_banner!
98
+ end
99
+
100
+ options.number_of_objects = [1000] if options.number_of_objects.empty?
101
+ options.outputs = [OpenStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
102
+
103
+ print_options( options )
104
+
105
+ options
106
+ end
107
+ end
@@ -0,0 +1,15 @@
1
+ # Taken from http://www.programmingishard.com/posts/show/128
2
+ # Posted by rbates
3
+ class Float
4
+ def round_to(x)
5
+ (self * 10**x).round.to_f / 10**x
6
+ end
7
+
8
+ def ceil_to(x)
9
+ (self * 10**x).ceil.to_f / 10**x
10
+ end
11
+
12
+ def floor_to(x)
13
+ (self * 10**x).floor.to_f / 10**x
14
+ end
15
+ end