napa 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,126 @@
1
+ require 'thor'
2
+ require 'active_support/all'
3
+ require 'napa/cli/generated_attribute'
4
+
5
+ module Napa
6
+ module CLI
7
+ class Error < Thor::Error # :nodoc:
8
+ end
9
+
10
+ # Note: This currently does not support namespaced model creation.
11
+ class Model < Thor::Group
12
+ include Thor::Actions
13
+
14
+ # Largely modeled off of Rails's:
15
+ # - activerecord/lib/rails/generators/active_record/model/model_generator.rb,
16
+ # - railties/lib/rails/generators/base.rb, and
17
+ # - railties/lib/rails/generators/named_base.rb
18
+
19
+ argument :name
20
+ argument :attributes, :type => :array, :default => []
21
+
22
+ class_option :migration, :type => :boolean, :default => true
23
+ class_option :timestamps, :type => :boolean, :default => true
24
+ class_option :indexes, :type => :boolean, :default => true
25
+ class_option :parent, :type => :string
26
+
27
+ def parse_attributes!
28
+ self.attributes = (attributes || []).map do |attr|
29
+ GeneratedAttribute.parse(attr)
30
+ end
31
+ end
32
+
33
+ def generate_model
34
+ # In order to check for class collisions, the Grape environment needs to be loaded.
35
+ say 'Generating model...'
36
+ self.class.source_root "#{File.dirname(__FILE__)}/templates"
37
+ create_migration_file
38
+ create_model_file
39
+ create_factory_file
40
+ create_model_spec_file
41
+ say 'Done!', :green
42
+ end
43
+
44
+ protected
45
+
46
+ def version
47
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
48
+ end
49
+
50
+ def create_migration_file
51
+ return unless options[:migration] && options[:parent].nil?
52
+ attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
53
+
54
+ # This does not currently check for similar migrations.
55
+ # This can be done by overriding the CreateFile Thor action and
56
+ # implementing the exists? and on_conflict_behavior methods.
57
+ template migration_template, "#{migration_output_directory}/#{version}_#{migration_name}.rb"
58
+ end
59
+
60
+ def create_model_file
61
+ template model_template, "#{model_output_directory}/#{model_name}.rb"
62
+ end
63
+
64
+ def create_factory_file
65
+ template factory_template, "#{factory_output_directory}/#{table_name}.rb"
66
+ end
67
+
68
+ def create_model_spec_file
69
+ template model_spec_template, "#{model_spec_output_directory}/#{model_name}_spec.rb"
70
+ end
71
+
72
+ def model_name
73
+ name.underscore
74
+ end
75
+
76
+ def migration_name
77
+ "create_#{table_name}"
78
+ end
79
+
80
+ def table_name
81
+ model_name.pluralize
82
+ end
83
+
84
+ def migration_template
85
+ "model/db/migrate/migration.rb.tt"
86
+ end
87
+
88
+ def parent_class_name
89
+ options[:parent] || "ActiveRecord::Base"
90
+ end
91
+
92
+ def migration_output_directory
93
+ './db/migrate'
94
+ end
95
+
96
+ def model_template
97
+ "model/app/models/model.rb.tt"
98
+ end
99
+
100
+ def model_output_directory
101
+ './app/models'
102
+ end
103
+
104
+ def factory_template
105
+ "model/spec/factories/factory.rb.tt"
106
+ end
107
+
108
+ def factory_output_directory
109
+ './spec/factories'
110
+ end
111
+
112
+ def model_spec_template
113
+ "model/spec/models/model_spec.rb.tt"
114
+ end
115
+
116
+ def model_spec_output_directory
117
+ './spec/models'
118
+ end
119
+
120
+ def attributes_with_index
121
+ attributes.select { |a| !a.reference? && a.has_index? }
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,9 @@
1
+ class <%= model_name.camelize %> < <%= parent_class_name.classify %>
2
+ <% attributes.select(&:reference?).each do |attribute| -%>
3
+ belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %><%= ', required: true' if attribute.required? %>
4
+ <% end -%>
5
+ <% if attributes.any?(&:password_digest?) -%>
6
+ # Note: This requires bcrypt to be added to your Gemfile.
7
+ has_secure_password
8
+ <% end -%>
9
+ end
@@ -0,0 +1,14 @@
1
+ FactoryGirl.define do
2
+ factory :<%= model_name %> do
3
+ <% attributes.each do |attribute| -%>
4
+ <% if attribute.reference? -%>
5
+ association :<%= attribute.name %>
6
+ <% elsif attribute.password_digest? -%>
7
+ password <%= attribute.factory_stub %>
8
+ password_confirmation <%= attribute.factory_stub %>
9
+ <% else -%>
10
+ <%= attribute.name %> <%= attribute.factory_stub %>
11
+ <% end -%>
12
+ <% end -%>
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= model_name.camelize %> do
4
+
5
+ it 'can be created' do
6
+ <%= model_name %> = create :<%= model_name %>
7
+ expect(<%= model_name %>).to_not be_nil
8
+ end
9
+
10
+ it 'needs tests to be written!' do
11
+ pending('write tests for <%= model_name.camelize.classify %>!')
12
+ end
13
+
14
+ end
@@ -4,6 +4,7 @@ ruby "2.0.0"
4
4
  gem 'rack-cors'
5
5
  gem '<%= @database_gem %>'
6
6
  gem 'activerecord', '~> 4.0.0', :require => 'active_record'
7
+ gem 'hashie-forbidden_attributes'
7
8
  gem 'honeybadger', '~> 1.16.7'
8
9
  gem 'json'
9
10
  gem 'napa'
@@ -34,7 +34,11 @@ module Napa
34
34
 
35
35
  if env['HTTP_PASSWORDS'].present?
36
36
  possible_passwords = env['HTTP_PASSWORDS'].to_s.split(',')
37
- (@allowed_header_passwords & possible_passwords).any?
37
+ successful_auth = (@allowed_header_passwords & possible_passwords).any?
38
+ return successful_auth if successful_auth
39
+
40
+ # check old header password if the new one fails
41
+ @old_allowed_passwords.include? env['HTTP_PASSWORD']
38
42
  else
39
43
  @old_allowed_passwords.include? env['HTTP_PASSWORD']
40
44
  end
@@ -29,6 +29,10 @@ module Napa
29
29
  expect(result_count).to eq(count)
30
30
  end
31
31
 
32
+ def expect_error_code(error_code)
33
+ expect(parsed_response.error.code).to eq(error_code.to_s)
34
+ end
35
+
32
36
  def expect_only(object)
33
37
  expect_count_of 1
34
38
  expect(first_result.id).to eq(object.id)
@@ -18,7 +18,7 @@ module Napa
18
18
  end
19
19
 
20
20
  def env
21
- @_env ||= ActiveSupport::StringInquirer.new(ENV['RACK_ENV'] || 'development')
21
+ @_env ||= ActiveSupport::StringInquirer.new(lookup_env)
22
22
  end
23
23
 
24
24
  def env=(environment)
@@ -32,5 +32,9 @@ module Napa
32
32
  def cache=(store_option)
33
33
  @_cache = ActiveSupport::Cache.lookup_store(store_option)
34
34
  end
35
+
36
+ def lookup_env
37
+ ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
38
+ end
35
39
  end
36
40
  end
@@ -1,5 +1,5 @@
1
1
  module Napa
2
- VERSION = '0.4.3'
2
+ VERSION = '0.5.0'
3
3
 
4
4
  class Version
5
5
  class << self
@@ -27,6 +27,9 @@ unless defined?(Rails)
27
27
  options = {}.tap do |o|
28
28
  o[:adapter] = db['adapter']
29
29
  o[:database] = 'postgres' if db['adapter'] == 'postgresql'
30
+ %w(host port username password).each do |f|
31
+ o[f.to_sym] = db[f] if db.has_key? f
32
+ end
30
33
  end
31
34
 
32
35
  ActiveRecord::Base.establish_connection(options)
@@ -41,6 +44,9 @@ unless defined?(Rails)
41
44
  options = {}.tap do |o|
42
45
  o[:adapter] = db['adapter']
43
46
  o[:database] = 'postgres' if db['adapter'] == 'postgresql'
47
+ %w(host port username password).each do |f|
48
+ o[f.to_sym] = db[f] if db.has_key? f
49
+ end
44
50
  end
45
51
 
46
52
  ActiveRecord::Base.establish_connection(options)
@@ -18,25 +18,25 @@ Gem::Specification.new do |gem|
18
18
  gem.required_ruby_version = '>= 2.0'
19
19
 
20
20
 
21
- gem.add_dependency 'rake', '~> 10.3'
22
- gem.add_dependency 'logging', '~> 1.8'
23
- gem.add_dependency 'dotenv', '~> 1.0'
24
- gem.add_dependency 'octokit', '~> 3.5'
25
- gem.add_dependency 'thor', '~> 0.19'
26
- gem.add_dependency 'virtus', '~> 1.0'
27
- gem.add_dependency 'grape', '~> 0.9'
28
- gem.add_dependency 'grape-swagger', '~> 0.8'
29
- gem.add_dependency 'roar', '~> 0.12'
30
- gem.add_dependency 'statsd-ruby', '~> 1.2'
31
- gem.add_dependency 'racksh', '~> 1.0'
32
- gem.add_dependency 'git', '~> 1.2'
33
- gem.add_dependency 'actionpack', '>= 3.2'
21
+ gem.add_dependency 'rake', '~> 10.3.0'
22
+ gem.add_dependency 'logging', '~> 1.8.0'
23
+ gem.add_dependency 'dotenv', '~> 1.0.0'
24
+ gem.add_dependency 'octokit', '~> 3.5.0'
25
+ gem.add_dependency 'thor', '~> 0.19.0'
26
+ gem.add_dependency 'virtus', '~> 1.0.0'
27
+ gem.add_dependency 'grape', '~> 0.9.0'
28
+ gem.add_dependency 'grape-swagger', '~> 0.8.0'
29
+ gem.add_dependency 'roar', '~> 0.12.0'
30
+ gem.add_dependency 'statsd-ruby', '~> 1.2.0'
31
+ gem.add_dependency 'racksh', '~> 1.0.0'
32
+ gem.add_dependency 'git', '~> 1.2.0'
33
+ gem.add_dependency 'actionpack', '>= 3.2.0'
34
34
 
35
- gem.add_development_dependency 'rspec', '~> 3.1'
36
- gem.add_development_dependency 'pry', '~> 0.10'
37
- gem.add_development_dependency 'rubocop', '~> 0.25'
38
- gem.add_development_dependency 'activerecord', '~> 3.2'
39
- gem.add_development_dependency 'sqlite3', '~> 1.3'
35
+ gem.add_development_dependency 'rspec', '~> 3.1.0'
36
+ gem.add_development_dependency 'pry', '~> 0.10.0'
37
+ gem.add_development_dependency 'rubocop', '~> 0.25.0'
38
+ gem.add_development_dependency 'activerecord', '~> 3.2.0'
39
+ gem.add_development_dependency 'sqlite3', '~> 1.3.0'
40
40
  gem.add_development_dependency 'acts_as_fu', '~> 0'
41
41
  gem.add_development_dependency 'codeclimate-test-reporter'
42
42
  end
@@ -24,13 +24,6 @@ describe Napa::CLI::Generate do
24
24
  expect(api_code).to match(/class FoosApi/)
25
25
  end
26
26
 
27
- it 'creates a model class' do
28
- expected_model_file = File.join(test_api_directory, 'app/models/foo.rb')
29
- model_code = File.read(expected_model_file)
30
-
31
- expect(model_code).to match(/class Foo/)
32
- end
33
-
34
27
  it 'creates a representer class' do
35
28
  expected_representer_file = File.join(test_api_directory, 'app/representers/foo_representer.rb')
36
29
  representer_code = File.read(expected_representer_file)
@@ -52,13 +45,6 @@ describe Napa::CLI::Generate do
52
45
 
53
46
  expect(api_code).to match(/describe FoosApi/)
54
47
  end
55
-
56
- it 'creates a model spec' do
57
- expected_model_file = File.join(test_api_directory, 'spec/models/foo_spec.rb')
58
- model_code = File.read(expected_model_file)
59
-
60
- expect(model_code).to match(/describe Foo/)
61
- end
62
48
  end
63
49
 
64
50
  end
@@ -0,0 +1,297 @@
1
+ require 'spec_helper'
2
+ require 'napa/cli/model'
3
+
4
+ describe Napa::CLI::Model do
5
+ let(:test_output_directory) { 'spec/tmp' }
6
+ let(:version) { '20000101000000' }
7
+
8
+ silence_thor
9
+
10
+ before do
11
+ allow_any_instance_of(described_class).to receive(:model_output_directory).and_return(test_output_directory)
12
+ allow_any_instance_of(described_class).to receive(:migration_output_directory).and_return(test_output_directory)
13
+ allow_any_instance_of(described_class).to receive(:factory_output_directory).and_return(test_output_directory)
14
+ allow_any_instance_of(described_class).to receive(:model_spec_output_directory).and_return(test_output_directory)
15
+ allow_any_instance_of(described_class).to receive(:version).and_return(version)
16
+ end
17
+
18
+ after do
19
+ FileUtils.rm_rf(test_output_directory)
20
+ end
21
+
22
+ describe 'Car model' do
23
+ before do
24
+ model = Napa::CLI::Model.new([ 'Car',
25
+ 'transmission_type:references',
26
+ 'has_navigation:boolean' ],
27
+ [ '--parent=Vehicle' ])
28
+ model.invoke_all
29
+
30
+ # The migration should not be created because a parent model is specified.
31
+ @migration_file = File.join(test_output_directory, "#{version}_create_cars.rb")
32
+
33
+ expected_model_file = File.join(test_output_directory, 'car.rb')
34
+ @model_content = File.read(expected_model_file)
35
+
36
+ expected_model_spec_file = File.join(test_output_directory, 'car_spec.rb')
37
+ @model_spec_content = File.read(expected_model_spec_file)
38
+
39
+ expected_factory_file = File.join(test_output_directory, 'cars.rb')
40
+ @factory_content = File.read(expected_factory_file)
41
+ end
42
+
43
+ describe 'migration' do
44
+ it 'is not created' do
45
+ expect(File.exists?(@migration_file)).to eq(false)
46
+ end
47
+ end
48
+
49
+ describe 'model' do
50
+ it 'creates a model class' do
51
+ expect(@model_content).to match(/class Car/)
52
+ end
53
+
54
+ it 'model inherits from ActiveRecord::Base' do
55
+ expect(@model_content).to match(/Car < Vehicle/)
56
+ end
57
+
58
+ it 'adds belongs_to association for references attributes' do
59
+ expect(@model_content).to match(/belongs_to :transmission_type/)
60
+ end
61
+ end
62
+
63
+ describe 'model spec' do
64
+ it 'loads the spec_helper' do
65
+ expect(@model_spec_content).to match(/require 'spec_helper'/)
66
+ end
67
+
68
+ it 'describes the model' do
69
+ expect(@model_spec_content).to match(/describe Car/)
70
+ end
71
+
72
+ it 'tests the creation of an model instance' do
73
+ expect(@model_spec_content).to match(/car = create :car/)
74
+ end
75
+
76
+ it 'creates a pending test' do
77
+ expect(@model_spec_content).to match(/pending\('.*'\)/)
78
+ end
79
+ end
80
+
81
+ describe 'factory' do
82
+ it 'creates a factory for the model' do
83
+ expect(@factory_content).to match(/factory :car/)
84
+ end
85
+
86
+ it 'creates a stub for each attribute' do
87
+ expect(@factory_content).to match(/association :transmission_type/)
88
+ expect(@factory_content).to match(/has_navigation false/)
89
+ end
90
+ end
91
+
92
+ after do
93
+ FileUtils.rm_rf(test_output_directory)
94
+ end
95
+ end
96
+
97
+ describe 'User model' do
98
+ before do
99
+ Napa::CLI::Model.new([ 'User',
100
+ 'username:string:index',
101
+ 'password:digest',
102
+ 'referrer:references',
103
+ 'birth_date:date:index' ]).invoke_all
104
+
105
+ expected_migration_file = File.join(test_output_directory, "#{version}_create_users.rb")
106
+ @migration_content = File.read(expected_migration_file)
107
+
108
+ expected_model_file = File.join(test_output_directory, 'user.rb')
109
+ @model_content = File.read(expected_model_file)
110
+
111
+ expected_model_spec_file = File.join(test_output_directory, 'user_spec.rb')
112
+ @model_spec_content = File.read(expected_model_spec_file)
113
+
114
+ expected_factory_file = File.join(test_output_directory, 'users.rb')
115
+ @factory_content = File.read(expected_factory_file)
116
+ end
117
+
118
+ describe 'migration' do
119
+ it 'creates a creates a camelized migration class' do
120
+ expect(@migration_content).to match(/class CreateUsers/)
121
+ end
122
+
123
+ it 'creates a table for the new model' do
124
+ expect(@migration_content).to match(/create_table :users/)
125
+ end
126
+
127
+ it 'adds the specified columns' do
128
+ expect(@migration_content).to match(/t.string :username/)
129
+ end
130
+
131
+ it 'adds the specified associations' do
132
+ expect(@migration_content).to match(/t.references :referrer/)
133
+ end
134
+
135
+ it 'adds password digest column' do
136
+ expect(@migration_content).to match(/t.string :password_digest/)
137
+ end
138
+
139
+ it 'adds the necessary indexes' do
140
+ expect(@migration_content).to match(/add_index :users, :username/)
141
+ expect(@migration_content).to match(/:referrer, index: true/)
142
+ expect(@migration_content).to match(/add_index :users, :birth_date/)
143
+ end
144
+ end
145
+
146
+ describe 'model' do
147
+ it 'creates a model class' do
148
+ expect(@model_content).to match(/class User/)
149
+ end
150
+
151
+ it 'model inherits from ActiveRecord::Base' do
152
+ expect(@model_content).to match(/User < ActiveRecord::Base/)
153
+ end
154
+
155
+ it 'adds has_secure_password for password digest attributes' do
156
+ expect(@model_content).to match(/has_secure_password/)
157
+ end
158
+ end
159
+
160
+ describe 'model spec' do
161
+ it 'loads the spec_helper' do
162
+ expect(@model_spec_content).to match(/require 'spec_helper'/)
163
+ end
164
+
165
+ it 'describes the model' do
166
+ expect(@model_spec_content).to match(/describe User/)
167
+ end
168
+
169
+ it 'tests the creation of an model instance' do
170
+ expect(@model_spec_content).to match(/user = create :user/)
171
+ end
172
+
173
+ it 'creates a pending test' do
174
+ expect(@model_spec_content).to match(/pending\('.*'\)/)
175
+ end
176
+ end
177
+
178
+ describe 'factory' do
179
+ it 'creates a factory for the model' do
180
+ expect(@factory_content).to match(/factory :user/)
181
+ end
182
+
183
+ it 'creates a stub for each attribute' do
184
+ expect(@factory_content).to match(/username "MyString"/)
185
+ expect(@factory_content).to match(/password "password"/)
186
+ expect(@factory_content).to match(/association :referrer/)
187
+ expect(@factory_content).to match(/birth_date { Date.today }/)
188
+ end
189
+
190
+ it 'creates a confirmation for password attributes' do
191
+ expect(@factory_content).to match(/password_confirmation "password"/)
192
+ end
193
+ end
194
+
195
+ after do
196
+ FileUtils.rm_rf(test_output_directory)
197
+ end
198
+ end
199
+
200
+ describe 'Gender model' do
201
+ before do
202
+ model = Napa::CLI::Model.new([ 'Gender',
203
+ 'name:string',
204
+ 'personal_characteristic:belongs_to{polymorphic}' ],
205
+ [ '--no-timestamps' ])
206
+ model.invoke_all
207
+
208
+ expected_migration_file = File.join(test_output_directory, "#{version}_create_genders.rb")
209
+ @migration_content = File.read(expected_migration_file)
210
+
211
+ expected_model_file = File.join(test_output_directory, 'gender.rb')
212
+ @model_content = File.read(expected_model_file)
213
+
214
+ expected_model_spec_file = File.join(test_output_directory, 'gender_spec.rb')
215
+ @model_spec_content = File.read(expected_model_spec_file)
216
+
217
+ expected_factory_file = File.join(test_output_directory, 'genders.rb')
218
+ @factory_content = File.read(expected_factory_file)
219
+ end
220
+
221
+ describe 'migration' do
222
+ it 'creates a migration class' do
223
+ expect(@migration_content).to match(/class CreateGenders/)
224
+ end
225
+
226
+ it 'creates a table for the new model' do
227
+ expect(@migration_content).to match(/create_table :genders/)
228
+ end
229
+
230
+ it 'adds the specified columns' do
231
+ expect(@migration_content).to match(/t.string :name/)
232
+ end
233
+
234
+ it 'adds the specified associations' do
235
+ expect(@migration_content).to match(/t.belongs_to :personal_characteristic/)
236
+ end
237
+
238
+ it 'sets up the polymorphic associations' do
239
+ expect(@migration_content).to match(/:personal_characteristic, polymorphic: true/)
240
+ end
241
+
242
+ it 'does NOT add timestamps to the table' do
243
+ expect(@migration_content).to_not match(/t.timestamps/)
244
+ end
245
+ end
246
+
247
+ describe 'model' do
248
+ it 'creates a model class' do
249
+ expect(@model_content).to match(/class Gender/)
250
+ end
251
+
252
+ it 'model inherits from ActiveRecord::Base' do
253
+ expect(@model_content).to match(/Gender < ActiveRecord::Base/)
254
+ end
255
+
256
+ it 'adds belongs_to associations' do
257
+ expect(@model_content).to match(/belongs_to :personal_characteristic/)
258
+ end
259
+
260
+ it 'sets up polymorphic associations' do
261
+ expect(@model_content).to match(/:personal_characteristic, polymorphic: true/)
262
+ end
263
+ end
264
+
265
+ describe 'model spec' do
266
+ it 'loads the spec_helper' do
267
+ expect(@model_spec_content).to match(/require 'spec_helper'/)
268
+ end
269
+
270
+ it 'describes the model' do
271
+ expect(@model_spec_content).to match(/describe Gender/)
272
+ end
273
+
274
+ it 'tests the creation of an model instance' do
275
+ expect(@model_spec_content).to match(/gender = create :gender/)
276
+ end
277
+
278
+ it 'creates a pending test' do
279
+ expect(@model_spec_content).to match(/pending\('.*'\)/)
280
+ end
281
+ end
282
+
283
+ describe 'factory' do
284
+ it 'creates a factory for the model' do
285
+ expect(@factory_content).to match(/factory :gender/)
286
+ end
287
+
288
+ it 'creates a stub for each attribute' do
289
+ expect(@factory_content).to match(/name "MyString"/)
290
+ end
291
+ end
292
+
293
+ after do
294
+ FileUtils.rm_rf(test_output_directory)
295
+ end
296
+ end
297
+ end