cockroach 0.0.0

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 (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