cockroach 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.rvmrc +1 -0
  2. data/Gemfile +28 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +124 -0
  5. data/Rakefile +37 -0
  6. data/VERSION +1 -0
  7. data/cockroach.gemspec +96 -0
  8. data/lib/cockroach.rb +43 -0
  9. data/lib/cockroach/base/load_nodes.rb +38 -0
  10. data/lib/cockroach/base/node.rb +192 -0
  11. data/lib/cockroach/base/node_structure.rb +11 -0
  12. data/lib/cockroach/config.rb +54 -0
  13. data/lib/cockroach/config/loader.rb +35 -0
  14. data/lib/cockroach/fixtures/factory_girl.rb +4 -0
  15. data/lib/cockroach/fixtures/factory_girl/loader.rb +43 -0
  16. data/lib/cockroach/fixtures/factory_girl/node.rb +51 -0
  17. data/lib/cockroach/fixtures/factory_girl/profiler.rb +34 -0
  18. data/lib/cockroach/railtie.rb +7 -0
  19. data/lib/cockroach/source.rb +40 -0
  20. data/lib/cockroach/source/model.rb +33 -0
  21. data/lib/cockroach/source/node.rb +27 -0
  22. data/lib/cockroach/version.rb +3 -0
  23. data/lib/generators/cockroach/install_generator.rb +20 -0
  24. data/lib/generators/cockroach/templates/cockroach.rb +8 -0
  25. data/lib/generators/cockroach/templates/faker.yml +16 -0
  26. data/lib/tasks/faker.rake +35 -0
  27. data/test/config/config_test.rb +129 -0
  28. data/test/config/loader_test.rb +42 -0
  29. data/test/fixturers/factory_girl/aliasing_test.rb +151 -0
  30. data/test/fixturers/factory_girl/loading_test.rb +45 -0
  31. data/test/fixturers/factory_girl/node_test.rb +386 -0
  32. data/test/fixturers/factory_girl/profiler_test.rb +124 -0
  33. data/test/fixturers/source_test.rb +153 -0
  34. data/test/generators/install_generator_test.rb +14 -0
  35. data/test/support/active_record.rb +11 -0
  36. data/test/support/data/correct_with_option.yml +13 -0
  37. data/test/support/data/correct_without_option.yml +10 -0
  38. data/test/support/data/dummy_structure/config/faker.yml +13 -0
  39. data/test/support/data/dummy_structure/config/user_only.yml +1 -0
  40. data/test/support/data/dummy_structure/config/witness.yml +6 -0
  41. data/test/support/data/dummy_structure/test/factories/user_factory.rb +16 -0
  42. data/test/support/database_cleaner.rb +13 -0
  43. data/test/support/factory_girl_mocked.rb +32 -0
  44. data/test/support/models/user.rb +23 -0
  45. data/test/test_helper.rb +26 -0
  46. metadata +151 -0
@@ -0,0 +1,11 @@
1
+ module Cockroach
2
+ module Base
3
+ # Simple idea. After that the nodes will be available as
4
+ # Cockroach::FactoryGirl::Node['top_node']['sub_mode']['sub_sub_node']
5
+ module NodeStructure
6
+ def [](name)
7
+ (@nodes ||= {})[name.to_s]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,54 @@
1
+ module Cockroach
2
+ class Config
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Loader
6
+ autoload :ConfigNotExistsError, 'cockroach/config/loader'
7
+
8
+ class MissingRootPathError < Exception; end
9
+
10
+ class << self
11
+ attr_writer :root
12
+ attr_accessor :fixturer, :config_path, :fixtures_path
13
+
14
+ # Returns root folder for the project, of if one is missing it tries to return
15
+ # Rails.root, if Rails is not defined it will raise an error.
16
+ def root
17
+ @root ||= begin
18
+ if defined?(Rails)
19
+ File.join Rails.root
20
+ else
21
+ "./"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ attr_reader :profile, :options, :fixtures_path
28
+
29
+ def initialize path_to_config
30
+ @config_path = File.expand_path path_to_config, self.class.root
31
+ @profile, @options = Cockroach::Config::Loader.parse(@config_path)
32
+ @fixturer_def = get_option('fixturer') || self.class.fixturer || 'factory_girl'
33
+ @fixtures_path = self.class.fixtures_path if self.class.fixtures_path
34
+ end
35
+
36
+ def fixturer
37
+ @fixturer ||= @fixturer_def.to_s.camelize.to_sym
38
+ end
39
+
40
+ def profiler
41
+ @profiler ||= begin
42
+ Cockroach.const_get(fixturer)::Profiler.new
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ # Options might not be specified at all. In that case @options will be nil
49
+ # This method will return nil, if option unavailable
50
+ def get_option option
51
+ @options[option.to_s] rescue nil
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ require "psych"
2
+ require "yaml"
3
+
4
+ module Cockroach
5
+ class Config
6
+ # Loader class just returns a structured and ready to use information
7
+ # parsed from faker project yaml file.
8
+ class ConfigNotExistsError < Exception; end
9
+
10
+ class Loader
11
+ CONSTRAINTS = %w(fixture_gem fixtures_path).freeze
12
+
13
+ class << self
14
+ # Load the file from the provided path, and return the contents as
15
+ # an Array, with the following structure:
16
+ #
17
+ # [
18
+ # { * Hash containg the amounts },
19
+ # { * Hash containing any other options or settings }
20
+ # ]
21
+ #
22
+ def parse path_to_config
23
+ raise ConfigNotExistsError.new("File under the path \"#{path_to_config}\", does not exists.") unless File.exists?(path_to_config)
24
+ contents = YAML.load_file path_to_config
25
+
26
+ options = contents.extract!(*CONSTRAINTS)
27
+ options.delete_if {|key, value| value == nil }
28
+ options = nil if options.blank?
29
+
30
+ [contents, options]
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,4 @@
1
+ require "factory_girl"
2
+ require "cockroach/fixtures/factory_girl/loader"
3
+ require "cockroach/fixtures/factory_girl/profiler"
4
+ require "cockroach/fixtures/factory_girl/node"
@@ -0,0 +1,43 @@
1
+ module Cockroach
2
+ module FactoryGirl
3
+
4
+ class NoExistingPathError < Exception; end
5
+
6
+ # Loader class is designed to load the FactoryGirl fixtures, defined
7
+ # in the project.
8
+ class Loader
9
+ class << self
10
+ def load
11
+ if factory_items.blank?
12
+ old_paths = ::FactoryGirl.definition_file_paths
13
+ if Cockroach.config.fixtures_path
14
+ ::FactoryGirl.definition_file_paths = [Cockroach.config.fixtures_path]
15
+ else
16
+ ::FactoryGirl.definition_file_paths = old_paths.collect { |path| File.join(Cockroach::Config.root, path) }
17
+ end
18
+
19
+ # Italiano spagetti
20
+ unless ::FactoryGirl.definition_file_paths.inject(false) { |valid, path| valid || File.exists?("#{path}.rb") || File.directory?(path) }
21
+ raise NoExistingPathError.new("Neither of the paths are valid: #{::FactoryGirl.definition_file_paths.inspect}")
22
+ end
23
+
24
+ ::FactoryGirl.find_definitions
25
+ ::FactoryGirl.definition_file_paths = old_paths
26
+ end
27
+ end
28
+
29
+ def load!
30
+ factory_items.clear
31
+ load
32
+ end
33
+
34
+ protected
35
+
36
+ def factory_items
37
+ ::FactoryGirl.factories.instance_variable_get(:@items)
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,51 @@
1
+ module Cockroach
2
+ module FactoryGirl
3
+ # Node deals only with a specific records class. It makes sure that
4
+ # fixtures are created specific amount of time and will make sure that
5
+ # the associations are correctly assigned.
6
+ class Node < ::Cockroach::Base::Node
7
+ def after_initialize
8
+ @factory = ::FactoryGirl.factory_by_name(@name)
9
+ end
10
+
11
+ def load! factory_opts = nil
12
+ if factory_opts
13
+ normalised_opts = factory_opts.dup
14
+ @aliases.each_pair { |k,v| normalised_opts[k] = normalised_opts.delete(v) } if @aliases
15
+ normalised_opts.keep_if {|k,v| allowed_options.include? k }
16
+ end
17
+
18
+ amount.times do
19
+ current_factory = generate_current_factory(normalised_opts)
20
+ ids << current_factory.id
21
+ unless nodes.blank?
22
+ load_nodes! (factory_opts || {}).merge({ node_name => current_factory})
23
+ end
24
+ end
25
+ end
26
+
27
+ protected
28
+
29
+ def generate_current_factory options
30
+ if @source
31
+ ret = @source.sample
32
+ ret.update_attributes(options) unless options.blank?
33
+ ret
34
+ else
35
+ options.blank? ?
36
+ ::FactoryGirl.create(name) :
37
+ ::FactoryGirl.create(name, options)
38
+ end
39
+ end
40
+
41
+ def allowed_options
42
+ @allowed_options ||= @factory.send(:evaluator_class).attribute_list.names.map(&:to_s)
43
+ end
44
+
45
+ # Returns class deducted from factory
46
+ def orm_class
47
+ @factory.send(:class_name)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ require "cockroach/base/node_structure"
2
+
3
+ module Cockroach
4
+ module FactoryGirl
5
+ # Profiler does all the routine to fill the database.
6
+ class Profiler
7
+ include Cockroach::Base::LoadNodes
8
+ include Cockroach::Base::NodeStructure
9
+
10
+ def initialize config = Cockroach.config
11
+ @source = config.profile
12
+ @base_models = @source.keys
13
+ end
14
+
15
+ # This method will load all the mentioned records into database
16
+ def load
17
+ unless @loaded
18
+ Cockroach::FactoryGirl::Loader.load
19
+ @source.each_pair do |name, structure|
20
+ node = Cockroach::FactoryGirl::Node.new(name, structure)
21
+ nodes[node.node_name] = node
22
+ end
23
+ @loaded = true
24
+ end
25
+ end
26
+
27
+ # This method will load all the mentioned records into database
28
+ def load!
29
+ load unless @loaded
30
+ nodes.each_value(&:load!)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ module Cockroach
2
+ class Railtie < ::Rails::Railtie
3
+ rake_tasks do
4
+ load File.expand_path('../../tasks/faker.rake', __FILE__)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ module Cockroach
2
+ module Source
3
+ autoload :Node, 'cockroach/source/node'
4
+ autoload :Model, 'cockroach/source/model'
5
+
6
+ class << self
7
+ def get_source source_refs
8
+ if source_refs.is_a?(Hash) && source_refs.keys.include?('model')
9
+ get_model source_refs
10
+ else
11
+ get_node source_refs
12
+ end
13
+ end
14
+
15
+ protected
16
+
17
+ def get_model source_refs
18
+ model_name = source_refs.delete('model')
19
+ Cockroach::Source::Model.new model_name.to_s.constantize, source_refs
20
+ end
21
+
22
+ def get_node source_refs
23
+ return unless source_refs
24
+ if source_refs.is_a?(String)
25
+ source_path = [source_refs]
26
+ else
27
+ source_path = source_refs.flatten
28
+ while source_path.last.is_a? Hash
29
+ source_path << source_path.pop.flatten
30
+ end
31
+ end
32
+ source_path.flatten!
33
+ node = source_path.inject(::Cockroach.profiler) do |node_keeper, node_name|
34
+ node_keeper[node_name]
35
+ end
36
+ Cockroach::Source::Node.new node
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ module Cockroach
2
+ module Source
3
+ class Model
4
+ attr_reader :model
5
+
6
+ def initialize model, options = {}
7
+ @model = model
8
+ @options = options
9
+ end
10
+
11
+ # Returns a random record, among generated.
12
+ def sample
13
+ if @options.blank?
14
+ model.order('RAND()').first
15
+ else
16
+ if @options.has_key?("id")
17
+ find @options["id"]
18
+ elsif @options.has_key?("conditions")
19
+ model.order('RAND()').where(@options["conditions"]).first
20
+ end
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ # Find among the record generated by this node.
27
+ # Returns ORM instance object
28
+ def find id
29
+ model.find id
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ module Cockroach
2
+ module Source
3
+ class Node
4
+ attr_reader :node
5
+
6
+ def initialize node
7
+ @node = node
8
+ end
9
+
10
+ # Returns a random record, among generated.
11
+ def sample
12
+ return nil if node.ids.empty?
13
+ id = node.ids.sample
14
+ find id
15
+ end
16
+
17
+ protected
18
+
19
+ # Find among the record generated by this node.
20
+ # Returns ORM instance object
21
+ def find id
22
+ return nil if node.ids.empty?
23
+ node.send(:orm_class).find id
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Cockroach
2
+ VERSION = File.read(File.expand_path("./../../VERSION", __FILE__))
3
+ end
@@ -0,0 +1,20 @@
1
+ #require 'rails/generators/generated_attribute'
2
+
3
+ module Cockroach
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ desc "Copy Faker config file into projects configuration folder"
9
+
10
+ # all public methods in here will be run in order
11
+ def copy_config
12
+ template "faker.yml", "config/faker.yml"
13
+ end
14
+
15
+ def copy_initializer
16
+ template "cockroach.rb", "config/initializers/cockroach.rb"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ #Cockroach.setup do |c|
2
+ # c.root = Rails.root
3
+ # c.config_path = "config/faker.yml"
4
+ # c.fixtures_path = File.expand_path(File.join('../../../', 'test', 'factories'), __FILE__)
5
+ #
6
+ # #the only available fixturer now is factory girl
7
+ # #c.fixturer = "factory_girl"
8
+ #end
@@ -0,0 +1,16 @@
1
+ # This file contains all the information, required for Cockroach to
2
+ # configure the amount of the generated records for fake database.
3
+ # It just keep the amount of the records that is required to generate, hierarhy
4
+ # and some other details conserning the generation way.
5
+
6
+ user_amount: 1000
7
+
8
+ feeds_ratio: 1000
9
+
10
+ cities:
11
+ amount: 1000
12
+ places:
13
+ ratio:
14
+ lower_limit: 100
15
+ upper_limit: 1000
16
+ address_amount: 1
@@ -0,0 +1,35 @@
1
+ namespace :cockroach do
2
+ desc "Validate your Cockroach config before load it."
3
+ task :validate, [:config_path] => [:environment] do |task, args|
4
+ if Cockroach.config && args[:config_path]
5
+ Cockroach.config.config_path = args[:config_path]
6
+ elsif args[:config_path]
7
+ Cockroach.setup do |c|
8
+ c.config_path = args[:config_path]
9
+ end
10
+ end
11
+
12
+ puts "Considering factory location as: #{Cockroach.config.fixtures_path || Cockroach::Config.root}"
13
+
14
+ Cockroach.profiler.load
15
+ puts "Config file is valid!"
16
+ end
17
+
18
+ desc "Run Cockroach generator"
19
+ task :generate, [:config_path] => [:environment] do |task, args|
20
+ Rake::Task["cockroach:validate"].invoke(args[:config_path])
21
+
22
+ Cockroach.profiler.load!
23
+ end
24
+
25
+ desc "Trancate the database, load seeds and run Cockroach generator"
26
+ task :reload, [:config_path] => [:environment] do |task, args|
27
+ args.with_defaults(:config_path => 'config/faker.yml')
28
+
29
+ Rake::Task["db:drop"].invoke
30
+ Rake::Task["db:create"].invoke
31
+ Rake::Task["db:migrate"].invoke
32
+ Rake::Task["db:seed"].invoke
33
+ Rake::Task["cockroach:generate"].invoke(args[:config_path])
34
+ end
35
+ end
@@ -0,0 +1,129 @@
1
+ require "test_helper"
2
+
3
+ module Cockroach
4
+ class ConfigTest < Test::Unit::TestCase
5
+ setup do
6
+ Cockroach::Config.root = File.expand_path("../../support/data/dummy_structure", __FILE__)
7
+ end
8
+
9
+ context "Config path assumptions" do
10
+ should "have predefined root path" do
11
+ assert_equal File.expand_path("../../support/data/dummy_structure", __FILE__), Cockroach::Config.root
12
+ end
13
+
14
+ should "assume rails root is defined" do
15
+ Cockroach::Config.root = nil
16
+ Rails.stubs(:root).returns("/some/fancy/path")
17
+
18
+ assert_equal "/some/fancy/path", Cockroach::Config.root
19
+ end
20
+
21
+ # should "assume rails root is not defined" do
22
+ # Cockroach::Config.root = nil
23
+ #
24
+ # Object.stubs(:defined?).with(Rails).returns(false)
25
+ #
26
+ # assert_raise Cockroach::Config::MissingRootPathError do
27
+ # Cockroach::Config.root
28
+ # end
29
+ # end
30
+
31
+ should "deduct root path from relative path" do
32
+ config = Cockroach::Config.new "../correct_with_option.yml"
33
+
34
+ assert config
35
+ end
36
+
37
+ should "deduct root path from absolute path" do
38
+ config = Cockroach::Config.new File.expand_path("../correct_with_option.yml", Cockroach::Config.root)
39
+
40
+ assert config
41
+ end
42
+ end
43
+
44
+ context "Fixturers" do
45
+ context "FactoryGirl" do
46
+ should "be default" do
47
+ config = Cockroach::Config.new "../correct_with_option.yml"
48
+
49
+ assert_equal :FactoryGirl, config.fixturer
50
+ end
51
+ end
52
+ end
53
+
54
+ context "Profiler" do
55
+ setup do
56
+ Cockroach.setup {|config|}
57
+ end
58
+
59
+ should "be delegated" do
60
+ assert_instance_of Cockroach::FactoryGirl::Profiler, Cockroach.profiler
61
+ end
62
+
63
+ should "create and keep new profiler" do
64
+ assert_instance_of Cockroach::FactoryGirl::Profiler, Cockroach.config.profiler
65
+ end
66
+
67
+ should "hit profiler once" do
68
+ ::Cockroach::FactoryGirl::Profiler.expects(:new).once.returns(true)
69
+
70
+ Cockroach.config.profiler
71
+ Cockroach.config.profiler
72
+ end
73
+ end
74
+ end
75
+
76
+ class SetupTest < Test::Unit::TestCase
77
+ context "Config class" do
78
+ def setup
79
+ @old = Cockroach::Config.dup
80
+ end
81
+
82
+ def teardown
83
+ silence_warnings { Cockroach.const_set('Config', @old) }
84
+ end
85
+
86
+ should "set root" do
87
+ Cockroach.setup do |c|
88
+ c.root = File.expand_path("../../support/data/dummy_structure", __FILE__)
89
+ end
90
+
91
+ assert_equal File.expand_path("../../support/data/dummy_structure", __FILE__), Cockroach::Config.root
92
+
93
+ end
94
+
95
+ should "set config_path" do
96
+ Cockroach.setup do |c|
97
+ c.root = File.expand_path("../../support/data/", __FILE__)
98
+ c.config_path = "./correct_with_option.yml"
99
+ end
100
+
101
+ assert_equal File.expand_path("../../support/data/correct_with_option.yml", __FILE__), Cockroach.config.instance_variable_get(:@config_path)
102
+ end
103
+
104
+ should "set fixtures_path" do
105
+ Cockroach.setup do |c|
106
+ c.root = File.expand_path("../../support/data/", __FILE__)
107
+ c.config_path = "./correct_with_option.yml"
108
+ c.fixtures_path = "some path to fixtures"
109
+ end
110
+
111
+ assert_equal "some path to fixtures", Cockroach.config.instance_variable_get(:@fixtures_path)
112
+ end
113
+
114
+ should "set fixturer" do
115
+ Object.const_set('FactoryBoy', mock('factory-boy'))
116
+ Cockroach.setup do |c|
117
+ c.root = File.expand_path("../../support/data/dummy_structure", __FILE__)
118
+ c.fixturer = :factory_boy
119
+ end
120
+
121
+ config = Cockroach.config
122
+
123
+ assert_equal :FactoryBoy, config.fixturer
124
+ Object.__send__(:remove_const,'FactoryBoy')
125
+ end
126
+ end
127
+
128
+ end
129
+ end