napa 0.4.3 → 0.5.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.
@@ -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