cranium 0.2.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 (132) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +3 -0
  8. data/Vagrantfile +24 -0
  9. data/bin/cranium +9 -0
  10. data/config/cucumber.yml +9 -0
  11. data/cranium.gemspec +26 -0
  12. data/db/setup.sql +8 -0
  13. data/docker-compose.yml +8 -0
  14. data/examples/config.rb +14 -0
  15. data/examples/deduplication.rb +27 -0
  16. data/examples/import_csv_with_field_lookup_inserting_new_dimension_keys.rb +26 -0
  17. data/examples/incremental_extract.rb +17 -0
  18. data/examples/lookup_with_multiple_fields.rb +25 -0
  19. data/features/archive.feature +49 -0
  20. data/features/extract/incremental_extract.feature +56 -0
  21. data/features/extract/simple_extract.feature +85 -0
  22. data/features/import/import_csv_to_database_as_delta.feature +38 -0
  23. data/features/import/import_csv_to_database_with_delete_insert_merging.feature +51 -0
  24. data/features/import/import_csv_to_database_with_truncate_insert.feature +49 -0
  25. data/features/import/import_csv_to_database_with_update_merging.feature +46 -0
  26. data/features/import/import_csv_with_always_inserting_new_dimension_keys.feature +137 -0
  27. data/features/import/import_csv_with_field_lookup_inserting_new_dimension_keys.feature +62 -0
  28. data/features/import/import_csv_with_field_lookup_transformation.feature +125 -0
  29. data/features/import/import_csv_with_transformation.feature +55 -0
  30. data/features/import/import_multiple_csv_files_without_transformations.feature +44 -0
  31. data/features/import/import_with_load_id_from_sequence.feature +53 -0
  32. data/features/import/import_with_lookup_from_multiple_fields.feature +64 -0
  33. data/features/read.feature +56 -0
  34. data/features/remove.feature +44 -0
  35. data/features/restore_database_connection.feature +55 -0
  36. data/features/step_definitions/database_table_steps.rb +40 -0
  37. data/features/step_definitions/definition_steps.rb +3 -0
  38. data/features/step_definitions/execution_steps.rb +23 -0
  39. data/features/step_definitions/file_steps.rb +39 -0
  40. data/features/support/class_extensions.rb +24 -0
  41. data/features/support/env.rb +27 -0
  42. data/features/support/randomize.rb +22 -0
  43. data/features/support/stop_on_first_error.rb +5 -0
  44. data/features/transform/deduplication.feature +37 -0
  45. data/features/transform/empty_transformation.feature +72 -0
  46. data/features/transform/join.feature +180 -0
  47. data/features/transform/join_multiple_files_into_one_output_file.feature +46 -0
  48. data/features/transform/output_rows.feature +70 -0
  49. data/features/transform/projection.feature +34 -0
  50. data/features/transform/raw_ruby_transformation.feature +69 -0
  51. data/features/transform/split_field.feature +39 -0
  52. data/lib/cranium/application.rb +104 -0
  53. data/lib/cranium/archiver.rb +36 -0
  54. data/lib/cranium/attribute_dsl.rb +43 -0
  55. data/lib/cranium/command_line_options.rb +27 -0
  56. data/lib/cranium/configuration.rb +33 -0
  57. data/lib/cranium/data_importer.rb +35 -0
  58. data/lib/cranium/data_reader.rb +48 -0
  59. data/lib/cranium/data_transformer.rb +126 -0
  60. data/lib/cranium/database.rb +36 -0
  61. data/lib/cranium/definition_registry.rb +21 -0
  62. data/lib/cranium/dimension_manager.rb +65 -0
  63. data/lib/cranium/dsl/database_definition.rb +23 -0
  64. data/lib/cranium/dsl/extract_definition.rb +28 -0
  65. data/lib/cranium/dsl/import_definition.rb +50 -0
  66. data/lib/cranium/dsl/source_definition.rb +67 -0
  67. data/lib/cranium/dsl.rb +100 -0
  68. data/lib/cranium/extensions/file.rb +7 -0
  69. data/lib/cranium/extensions/sequel_greenplum.rb +30 -0
  70. data/lib/cranium/external_table.rb +75 -0
  71. data/lib/cranium/extract/data_extractor.rb +11 -0
  72. data/lib/cranium/extract/storage.rb +57 -0
  73. data/lib/cranium/extract/strategy/base.rb +27 -0
  74. data/lib/cranium/extract/strategy/incremental.rb +16 -0
  75. data/lib/cranium/extract/strategy/simple.rb +9 -0
  76. data/lib/cranium/extract/strategy.rb +7 -0
  77. data/lib/cranium/extract.rb +7 -0
  78. data/lib/cranium/import_strategy/base.rb +55 -0
  79. data/lib/cranium/import_strategy/delete_insert.rb +40 -0
  80. data/lib/cranium/import_strategy/delta.rb +8 -0
  81. data/lib/cranium/import_strategy/merge.rb +50 -0
  82. data/lib/cranium/import_strategy/truncate_insert.rb +19 -0
  83. data/lib/cranium/import_strategy.rb +9 -0
  84. data/lib/cranium/logging.rb +15 -0
  85. data/lib/cranium/profiling.rb +13 -0
  86. data/lib/cranium/progress_output.rb +37 -0
  87. data/lib/cranium/sequel/hash.rb +32 -0
  88. data/lib/cranium/sequel.rb +5 -0
  89. data/lib/cranium/source_registry.rb +21 -0
  90. data/lib/cranium/test_framework/cucumber_table.rb +140 -0
  91. data/lib/cranium/test_framework/database_entity.rb +29 -0
  92. data/lib/cranium/test_framework/database_sequence.rb +16 -0
  93. data/lib/cranium/test_framework/database_table.rb +33 -0
  94. data/lib/cranium/test_framework/upload_directory.rb +39 -0
  95. data/lib/cranium/test_framework/world.rb +66 -0
  96. data/lib/cranium/test_framework.rb +10 -0
  97. data/lib/cranium/transformation/duplication_index.rb +42 -0
  98. data/lib/cranium/transformation/index.rb +83 -0
  99. data/lib/cranium/transformation/join.rb +141 -0
  100. data/lib/cranium/transformation/sequence.rb +42 -0
  101. data/lib/cranium/transformation.rb +8 -0
  102. data/lib/cranium/transformation_record.rb +45 -0
  103. data/lib/cranium.rb +57 -0
  104. data/rake/test.rake +31 -0
  105. data/spec/cranium/application_spec.rb +166 -0
  106. data/spec/cranium/archiver_spec.rb +44 -0
  107. data/spec/cranium/command_line_options_spec.rb +32 -0
  108. data/spec/cranium/configuration_spec.rb +31 -0
  109. data/spec/cranium/data_importer_spec.rb +55 -0
  110. data/spec/cranium/data_transformer_spec.rb +16 -0
  111. data/spec/cranium/database_spec.rb +69 -0
  112. data/spec/cranium/definition_registry_spec.rb +45 -0
  113. data/spec/cranium/dimension_manager_spec.rb +63 -0
  114. data/spec/cranium/dsl/database_definition_spec.rb +23 -0
  115. data/spec/cranium/dsl/extract_definition_spec.rb +76 -0
  116. data/spec/cranium/dsl/import_definition_spec.rb +153 -0
  117. data/spec/cranium/dsl/source_definition_spec.rb +84 -0
  118. data/spec/cranium/dsl_spec.rb +119 -0
  119. data/spec/cranium/external_table_spec.rb +71 -0
  120. data/spec/cranium/extract/storage_spec.rb +125 -0
  121. data/spec/cranium/logging_spec.rb +37 -0
  122. data/spec/cranium/sequel/hash_spec.rb +56 -0
  123. data/spec/cranium/source_registry_spec.rb +31 -0
  124. data/spec/cranium/test_framework/cucumber_table_spec.rb +144 -0
  125. data/spec/cranium/transformation/duplication_index_spec.rb +75 -0
  126. data/spec/cranium/transformation/index_spec.rb +178 -0
  127. data/spec/cranium/transformation/join_spec.rb +43 -0
  128. data/spec/cranium/transformation/sequence_spec.rb +83 -0
  129. data/spec/cranium/transformation_record_spec.rb +78 -0
  130. data/spec/cranium_spec.rb +53 -0
  131. data/spec/spec_helper.rb +1 -0
  132. metadata +362 -0
@@ -0,0 +1,178 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Cranium::Transformation::Index do
4
+
5
+ let(:index) { Cranium::Transformation::Index.new }
6
+ let(:connection) { double "Greenplum connection" }
7
+ let(:dimension_manager) { double "DimensionManager" }
8
+
9
+ before(:each) do
10
+ allow(Cranium::Database).to receive(:connection).and_return(connection)
11
+ end
12
+
13
+
14
+
15
+ def stub_cache_query(table_name, key_fields, value_field, result)
16
+ allow(dimension_manager).to receive(:create_cache_for_field).with(value_field).and_return(result)
17
+ allow(Cranium::DimensionManager).to receive(:for).with(table_name, key_fields).and_return(dimension_manager)
18
+ end
19
+
20
+
21
+
22
+ describe "#lookup" do
23
+ context "the first time it's called" do
24
+ it "should query the requested key value from the database" do
25
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 1",
26
+ [2345] => "contact 2",
27
+ [3456] => "contact 3"}
28
+
29
+ expect(index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 2345)).to eq("contact 2")
30
+ end
31
+
32
+ it "should query the requested multi-key value from the database" do
33
+ stub_cache_query :dim_contact, [:key_1, :key_2], :contact_key, {[12, 34] => "contact 1",
34
+ [23, 45] => "contact 2",
35
+ [34, 56] => "contact 3"}
36
+
37
+ expect(index.lookup(:contact_key, from_table: :dim_contact, match: {key_1: 23, key_2: 45})).to eq("contact 2")
38
+ end
39
+ end
40
+
41
+
42
+ context "on subsequent calls" do
43
+ it "should look up the requested value from an internal cache" do
44
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 1"}
45
+ index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 1234)
46
+
47
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 2"}
48
+ expect(index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 1234)).to eq("contact 1")
49
+ end
50
+ end
51
+
52
+
53
+ it "should return :not_found if the key value was not found" do
54
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 2"}
55
+
56
+ expect(index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 2345)).to eq(:not_found)
57
+ end
58
+
59
+
60
+ it "should raise an error if both :if_not_found_then_insert and :if_not_found_then are specified" do
61
+ expect do
62
+ index.lookup(:contact_key, if_not_found_then: -1, if_not_found_then_insert: {})
63
+ end.to raise_error ArgumentError, "Cannot specify both :if_not_found_then and :if_not_found_then_insert options"
64
+ end
65
+
66
+
67
+ context "when :if_not_found_then is specified" do
68
+ it "should return the specified value if the lookup failed" do
69
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact"}
70
+
71
+ expect(index.lookup(:contact_key,
72
+ from_table: :dim_contact,
73
+ match_column: :customer_id,
74
+ to_value: 2345,
75
+ if_not_found_then: -1)).to eq(-1)
76
+ end
77
+
78
+ context "when the specified value is a lamba expression" do
79
+ it "should evaluate the expression and return its value if the lookup failed" do
80
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact"}
81
+
82
+ expect(index.lookup(:contact_key,
83
+ from_table: :dim_contact,
84
+ match_column: :customer_id,
85
+ to_value: 2345,
86
+ if_not_found_then: -> { -1 })).to eq(-1)
87
+ end
88
+ end
89
+ end
90
+
91
+
92
+ context "when :if_not_found_then_insert is specified" do
93
+
94
+ before(:each) do
95
+ stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact"}
96
+ end
97
+
98
+ context "when a single key is used" do
99
+ it "should insert a new record into the specified table" do
100
+ expect(dimension_manager).to receive(:insert).with(:contact_key, {contact_key: 1, customer_id: 2345})
101
+
102
+ index.lookup :contact_key,
103
+ from_table: :dim_contact,
104
+ match_column: :customer_id,
105
+ to_value: 2345,
106
+ if_not_found_then_insert: {contact_key: 1, customer_id: 2345}
107
+ end
108
+ end
109
+
110
+ context "when multiple keys are used" do
111
+ it "should insert a new record into the specified table" do
112
+ stub_cache_query :dim_contact, [:key_1, :key_2], :contact_key, {[12, 34] => "contact"}
113
+
114
+ expect(dimension_manager).to receive(:insert).with(:contact_key, contact_key: 1, key_1: 23, key_2: 45)
115
+
116
+ index.lookup :contact_key,
117
+ from_table: :dim_contact,
118
+ match: {key_1: 23, key_2: 45},
119
+ if_not_found_then_insert: {contact_key: 1, key_1: 23, key_2: 45}
120
+ end
121
+ end
122
+
123
+ it "should fill out the new record's lookup key automatically" do
124
+ expect(dimension_manager).to receive(:insert).with(:contact_key, name: "new contact", customer_id: 2345)
125
+
126
+ index.lookup :contact_key,
127
+ from_table: :dim_contact,
128
+ match_column: :customer_id,
129
+ to_value: 2345,
130
+ if_not_found_then_insert: {name: "new contact"}
131
+ end
132
+
133
+ it "should overwrite the new record's lookup key if specified" do
134
+ expect(dimension_manager).to receive(:insert).with(:contact_key, customer_id: 2345)
135
+
136
+ index.lookup :contact_key,
137
+ from_table: :dim_contact,
138
+ match_column: :customer_id,
139
+ to_value: 2345,
140
+ if_not_found_then_insert: {customer_id: 4567}
141
+ end
142
+
143
+ it "should return the new record's lookup value" do
144
+ allow(dimension_manager).to receive_messages insert: 98765
145
+
146
+ expect(index.lookup(:contact_key,
147
+ from_table: :dim_contact,
148
+ match_column: :customer_id,
149
+ to_value: 2345,
150
+ if_not_found_then_insert: {contact_key: 98765})).to eq(98765)
151
+ end
152
+ end
153
+ end
154
+
155
+
156
+ describe "#insert" do
157
+ before(:each) do
158
+ stub_cache_query :dim_contact, [:contact_key], :contact_key, {[1234] => "contact"}
159
+ end
160
+
161
+ it "should insert a new record into the specified table" do
162
+ expect(dimension_manager).to receive(:insert).with(:contact_key, {contact_key: 1, customer_id: 2345})
163
+
164
+ index.insert :contact_key,
165
+ table: :dim_contact,
166
+ record: {contact_key: 1, customer_id: 2345}
167
+ end
168
+
169
+ it "should return the new record's lookup value" do
170
+ allow(dimension_manager).to receive_messages insert: 98765
171
+
172
+ expect(index.insert :contact_key,
173
+ table: :dim_contact,
174
+ record: {contact_key: 98765}).to eq(98765)
175
+ end
176
+ end
177
+
178
+ end
@@ -0,0 +1,43 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Cranium::Transformation::Join do
4
+
5
+ let(:join) { Cranium::Transformation::Join.new }
6
+
7
+ describe "#execute" do
8
+ context "when validating its parameters" do
9
+ before(:each) do
10
+ join.source_left = "left source"
11
+ join.source_right = "right source"
12
+ join.target = "target source"
13
+ join.match_fields = { field1: :field2 }
14
+ end
15
+
16
+ it "should raise an error if :source_left isn't set" do
17
+ join.source_left = nil
18
+ expect { join.execute }.to raise_error "Missing left source for join transformation"
19
+ end
20
+
21
+ it "should raise an error if :source_right isn't set" do
22
+ join.source_right = nil
23
+ expect { join.execute }.to raise_error "Missing right source for join transformation"
24
+ end
25
+
26
+ it "should raise an error if :target isn't set" do
27
+ join.target = nil
28
+ expect { join.execute }.to raise_error "Missing target for join transformation"
29
+ end
30
+
31
+ it "should raise an error if :match_fields is set but isn't a Hash" do
32
+ join.match_fields = :field
33
+ expect { join.execute }.to raise_error "Invalid match fields for join transformation"
34
+ end
35
+
36
+ it "should raise an error if :type is not supported" do
37
+ join.type = :cross
38
+ expect { join.execute }.to raise_error "Invalid type for join transformation"
39
+ end
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,83 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Cranium::Transformation::Sequence do
4
+
5
+ def stub_next_value(value)
6
+ dataset = double "dataset"
7
+ allow(dataset).to receive_messages first: { next_value: value }
8
+ allow(Cranium::Database).to receive_message_chain(:connection, :[]).with("SELECT nextval('id_seq') AS next_value").and_return(dataset)
9
+ end
10
+
11
+
12
+
13
+ let(:sequence) { Cranium::Transformation::Sequence.new :id_seq }
14
+
15
+ describe ".by_name" do
16
+ before(:each) { Cranium::Transformation::Sequence.instance_variable_set :@sequences, nil }
17
+
18
+ it "should return a sequence with the specified name" do
19
+ sequence = Cranium::Transformation::Sequence.by_name(:id_seq)
20
+
21
+ expect(sequence).to be_a Cranium::Transformation::Sequence
22
+ expect(sequence.name).to eq(:id_seq)
23
+ end
24
+
25
+ it "should schedule a newly created sequence's flush method as an after_import hook" do
26
+ expect(Cranium.application).to receive(:after_import).once
27
+
28
+ Cranium::Transformation::Sequence.by_name(:id_seq)
29
+ Cranium::Transformation::Sequence.by_name(:id_seq)
30
+ end
31
+
32
+ it "should memoize previously created instances" do
33
+ expect(Cranium::Transformation::Sequence.by_name(:id_seq)).to equal Cranium::Transformation::Sequence.by_name(:id_seq)
34
+ end
35
+ end
36
+
37
+
38
+ describe "#next_value" do
39
+ before(:each) do
40
+ stub_next_value 123
41
+ end
42
+
43
+ context "the first time it's called" do
44
+ it "should return the named sequence's next value read from the database" do
45
+ expect(sequence.next_value).to eq(123)
46
+ end
47
+ end
48
+
49
+ context "on subsequent calls" do
50
+ it "should increment its counter internally without querying the database" do
51
+ expect(sequence.next_value).to eq(123)
52
+
53
+ expect(Cranium::Database).not_to receive :connection
54
+
55
+ expect(sequence.next_value).to eq(124)
56
+ expect(sequence.next_value).to eq(125)
57
+ end
58
+ end
59
+ end
60
+
61
+
62
+ describe "#flush" do
63
+ let(:sequence) { Cranium::Transformation::Sequence.new :id_seq }
64
+
65
+ it "should not use the database if no value was ever requested from the sequence" do
66
+ expect(Cranium::Database).not_to receive :connection
67
+
68
+ sequence.flush
69
+ end
70
+
71
+ it "should set the database sequence's value to the last value returned" do
72
+ stub_next_value 123
73
+ sequence.next_value
74
+
75
+ connection = double "connection"
76
+ allow(Cranium::Database).to receive_messages connection: connection
77
+ expect(connection).to receive(:run).with("SELECT setval('id_seq', 123)")
78
+
79
+ sequence.flush
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,78 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Cranium::TransformationRecord do
4
+
5
+ let(:record) { Cranium::TransformationRecord.new [:field1, :field2, :field3], [:field1, :field2, :field3] }
6
+
7
+ describe "#input_data=" do
8
+ it "should set the input data row" do
9
+ record.input_data = ["one", "three", "five"]
10
+ expect(record.data).to eq({ :field1 => "one", :field2 => "three", :field3 => "five" })
11
+ end
12
+ end
13
+
14
+
15
+ describe "#[]" do
16
+ it "should access the fields of the record as if it were a Hash" do
17
+ record.input_data = ["one", "two", "three"]
18
+ expect(record[:field2]).to eq("two")
19
+ end
20
+ end
21
+
22
+
23
+ describe "#[]=" do
24
+ it "should set the fields of the record as if it were a Hash" do
25
+ record.input_data = ["one", "two", "three"]
26
+ record[:field2] = "four"
27
+ expect(record[:field2]).to eq("four")
28
+ end
29
+ end
30
+
31
+
32
+ describe "#split_field" do
33
+
34
+ let(:record) { Cranium::TransformationRecord.new [:source_field], [:target_field1, :target_field2] }
35
+
36
+ it "should store values into respective fields and drop extra values" do
37
+ record.input_data = ["first|second|third"]
38
+ record.split_field :source_field, into: [:target_field1, :target_field2], by: "|"
39
+ expect(record[:target_field1]).to eq("first")
40
+ expect(record[:target_field2]).to eq("second")
41
+ end
42
+
43
+ context "when default value is not set" do
44
+ it "should repeat last value when there are not enough values" do
45
+ record.input_data = ["first"]
46
+ record.split_field :source_field, into: [:target_field1, :target_field2], by: "|"
47
+ expect(record[:target_field1]).to eq("first")
48
+ expect(record[:target_field2]).to eq("first")
49
+ end
50
+ end
51
+
52
+ context "when default value is specified" do
53
+ it "should use default value when there are not enough values" do
54
+ record.input_data = ["first"]
55
+ record.split_field :source_field, into: [:target_field1, :target_field2], by: "|", default_value: "--"
56
+ expect(record[:target_field1]).to eq("first")
57
+ expect(record[:target_field2]).to eq("--")
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+
64
+ describe "#has_key?" do
65
+ it "should return true if the record contains data for the specified key" do
66
+ record.input_data = ["one", "two", "three"]
67
+
68
+ expect(record.has_key?(:field1)).to be_truthy
69
+ end
70
+
71
+ it "should return false if the record doesn't contain data for the specified key" do
72
+ record.input_data = ["one", "two", "three"]
73
+
74
+ expect(record.has_key?(:field4)).to be_falsey
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Cranium do
4
+
5
+ describe ".application" do
6
+ it "should return an Application object" do
7
+ expect(Cranium.application).to be_a Cranium::Application
8
+ end
9
+
10
+ it "should return a singleton" do
11
+ expect(Cranium.application).to equal Cranium.application
12
+ end
13
+ end
14
+
15
+
16
+ describe ".configure" do
17
+ it "should set or modify the existing configuration" do
18
+ Cranium.configure do |config|
19
+ config.greenplum_connection_string = "greenplum connection"
20
+ config.mysql_connection_string = "mysql connection"
21
+ end
22
+
23
+ Cranium.configure do |config|
24
+ config.greenplum_connection_string = "new greenplum connection"
25
+ end
26
+
27
+ expect(Cranium.configuration.greenplum_connection_string).to eq("new greenplum connection")
28
+ expect(Cranium.configuration.mysql_connection_string).to eq("mysql connection")
29
+ end
30
+ end
31
+
32
+
33
+ describe ".configuration" do
34
+ it "should return the configuration" do
35
+ expect(Cranium.configuration).to be_a Cranium::Configuration
36
+ end
37
+
38
+ it "should not let the user modify the configuration" do
39
+ expect { Cranium.configuration.greenplum_connection_string = "constring" }.to raise_error(RuntimeError)
40
+ end
41
+ end
42
+
43
+
44
+ describe ".load_arguments" do
45
+ it "should return the load arguments of the application" do
46
+ app = double "application", load_arguments: "load_arguments"
47
+ allow(Cranium).to receive(:application).and_return(app)
48
+
49
+ expect(Cranium.load_arguments).to eq "load_arguments"
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1 @@
1
+ require_relative '../lib/cranium'