rails-formation 0.0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +19 -0
  3. data/bin/formation +8 -0
  4. data/lib/rails-formation/cli/api_adapter.rb +15 -0
  5. data/lib/rails-formation/cli/file_adapter.rb +18 -0
  6. data/lib/rails-formation/cli/processor.rb +40 -0
  7. data/lib/rails-formation/formatters/factories/column.rb +63 -0
  8. data/lib/rails-formation/formatters/factories/default_value.rb +27 -0
  9. data/lib/rails-formation/formatters/factories/value.rb +78 -0
  10. data/lib/rails-formation/formatters/factory.rb +38 -0
  11. data/lib/rails-formation/formatters/migration.rb +45 -0
  12. data/lib/rails-formation/formatters/migrations/column.rb +33 -0
  13. data/lib/rails-formation/formatters/migrations/index.rb +30 -0
  14. data/lib/rails-formation/formatters/model.rb +42 -0
  15. data/lib/rails-formation/formatters/models/validation.rb +41 -0
  16. data/lib/rails-formation/formatters/models/validations/base.rb +62 -0
  17. data/lib/rails-formation/formatters/models/validations/comparsion.rb +31 -0
  18. data/lib/rails-formation/formatters/models/validations/confirmation.rb +19 -0
  19. data/lib/rails-formation/formatters/models/validations/exclusion.rb +25 -0
  20. data/lib/rails-formation/formatters/models/validations/format.rb +31 -0
  21. data/lib/rails-formation/formatters/models/validations/inclusion.rb +25 -0
  22. data/lib/rails-formation/formatters/models/validations/length.rb +58 -0
  23. data/lib/rails-formation/formatters/models/validations/numericality.rb +59 -0
  24. data/lib/rails-formation/formatters/models/validations/presence.rb +19 -0
  25. data/lib/rails-formation/formatters/models/validations/uniqueness.rb +58 -0
  26. data/lib/rails-formation/formatters/rubygem.rb +24 -0
  27. data/lib/rails-formation/formatters/rubygems/gem.rb +56 -0
  28. data/lib/rails-formation/formatters/seed.rb +30 -0
  29. data/lib/rails-formation/formatters/seeds/row.rb +19 -0
  30. data/lib/rails-formation/templates/factory.rb.tt +7 -0
  31. data/lib/rails-formation/templates/migration.rb.tt +16 -0
  32. data/lib/rails-formation/templates/model.rb.tt +7 -0
  33. data/lib/rails-formation/templates/seeds.rb.tt +3 -0
  34. data/lib/rails-formation/version.rb +6 -0
  35. data/lib/rails_formation.rb +99 -0
  36. data/rails-formation.gemspec +39 -0
  37. metadata +182 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ad157ec88ba25d8f9197ed69ad68c6a83ea79a92a38ca158c74582988b4af285
4
+ data.tar.gz: dcf51b0e646da2778ca9e813b8a550881af5a08e81cdb8de3e376a1655f68bed
5
+ SHA512:
6
+ metadata.gz: b3ffc89976c3718500ffaa12e5d96238af9dc090037fc80d648992d4705e55b058212caf86fce0afedb09fce4e70bf6ec7beb5770b1b7492ef971b046195a506
7
+ data.tar.gz: 14701d72714814a0041443f315ee8c06d857a8cbd3175bddc47b18f187d71c5d8daa4a305b2aebe10c55ecd842f8b291a1ff3bb1c0797300278d9f6e688aabc3
data/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # Rails formation
2
+
3
+ Plan and bootstrap Ruby on Rails application at the same time. Skip the boring part of the development. Visit https://railsformation.com and create your first formation.
4
+
5
+ ## 🚀 Installation
6
+
7
+ Install gem globally not per project:
8
+
9
+ ```shell
10
+ gem install rails-formation
11
+ ```
12
+
13
+ ## 📚 Usage
14
+
15
+ After you download formation from the project:
16
+
17
+ ```shell
18
+ formation apply template.json
19
+ ```
data/bin/formation ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rails-formation'
5
+
6
+ command_line_arguments = ARGV.dup
7
+
8
+ RailsFormation::Cli::Processor.new(command_line_arguments).call
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Cli
5
+ class ApiAdapter
6
+ def initialize(uid)
7
+ @uid = uid
8
+ end
9
+
10
+ def template
11
+ # pull from railsformation.com API
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module RailsFormation
6
+ module Cli
7
+ class FileAdapter
8
+ def initialize(file_path)
9
+ @file_path = file_path
10
+ end
11
+
12
+ def template
13
+ raw_json = File.read(@file_path)
14
+ JSON.parse(raw_json)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Cli
5
+ class Processor
6
+ COMMANDS = %w[apply].freeze
7
+
8
+ InvalidCommand = Class.new(StandardError)
9
+ InvalidUid = Class.new(StandardError)
10
+
11
+ def initialize(args)
12
+ @command = args[0]
13
+ @uid = args[1]
14
+ end
15
+
16
+ def call
17
+ validate_command
18
+
19
+ ::RailsFormation.apply(adapter.template)
20
+ end
21
+
22
+ private
23
+
24
+ def validate_command
25
+ raise InvalidCommand, "command #{@command} is not supported!" unless COMMANDS.include?(@command.to_s.downcase)
26
+ end
27
+
28
+ def adapter
29
+ case @uid
30
+ when /.*.json$/
31
+ ::RailsFormation::Cli::FileAdapter.new(@uid)
32
+ when /^rft-.*/
33
+ ::RailsFormation::Cli::ApiAdapter.new(@uid)
34
+ else
35
+ raise InvalidUid, "#{@uid} is not valid template file or UID"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'default_value'
4
+ require_relative 'value'
5
+
6
+ module RailsFormation
7
+ module Formatters
8
+ module Factories
9
+ class Column
10
+ def initialize(config)
11
+ @config = config
12
+ end
13
+
14
+ def to_s
15
+ if @config.key?('has_confirmation')
16
+ base_part = "#{name} { #{value} }"
17
+ "#{base_part}\n #{name}_confirmation { #{name} }"
18
+ else
19
+ "#{name} { #{value} }"
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def name
26
+ @config.fetch('name')
27
+ end
28
+
29
+ def sql_type
30
+ @config.fetch('sql_type')
31
+ end
32
+
33
+ def specialized
34
+ @config.fetch('specialized')
35
+ end
36
+
37
+ def use_sql_type?
38
+ specialized == 'default'
39
+ end
40
+
41
+ def default_value
42
+ ::RailsFormation::Formatters::Factories::DefaultValue
43
+ end
44
+
45
+ def value
46
+ if @config.key?('in')
47
+ "#{@config.fetch('in')}.sample"
48
+ else
49
+ raw_value
50
+ end
51
+ end
52
+
53
+ def raw_value
54
+ if use_sql_type?
55
+ ::RailsFormation::Formatters::Factories::DefaultValue.detect(sql_type)
56
+ else
57
+ ::RailsFormation::Formatters::Factories::Value.detect(specialized)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Factories
6
+ class DefaultValue
7
+ MAPPINGS = {
8
+ 'string' => 'FFaker::Lorem.sentence',
9
+ 'text' => 'FFaker::Lorem.sentence(50)',
10
+ 'boolean' => 'FFaker::Boolean.maybe',
11
+ 'time' => 'Time.zone.now',
12
+ 'date' => 'FFaker::Time.date',
13
+ 'float' => 'FFaker::Number.decimal',
14
+ 'decimal' => 'FFaker::Number.decimal',
15
+ 'integer' => 'FFaker::Number.number',
16
+ 'binary' => '',
17
+ 'timestamp' => 'Time.now.getutc',
18
+ 'datetime' => 'DateTime.now'
19
+ }.freeze
20
+
21
+ def self.detect(sql_type)
22
+ MAPPINGS[sql_type]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Factories
6
+ class Value
7
+ MAPPINGS = {
8
+ 'first_name' => 'FFaker::Name.first_name',
9
+ 'last_name' => 'FFaker::Name.last_name',
10
+ 'zip_code' => 'FFaker::AddressUS.zip_code',
11
+ 'state' => 'FFaker::AddressUS.state',
12
+ 'city' => 'FFaker::Address.city',
13
+ 'street_name' => 'FFaker::Address.street_name',
14
+ 'building_number' => 'FFaker::Address.building_number',
15
+ 'country_code' => 'FFaker::Address.country_code',
16
+ 'country' => 'FFaker::Address.country',
17
+ 'time_zone' => 'FFaker::Address.time_zone',
18
+ 'plane_name' => 'FFaker::Airline.name',
19
+ 'flight_number' => 'FFaker::Airline.flight_number',
20
+ 'animal' => 'FFaker::AnimalUS.common_name',
21
+ 'iban' => 'FFaker::Bank.iban',
22
+ 'card_number' => 'FFaker::Bank.card_number',
23
+ 'card_type' => 'FFaker::Bank.card_number',
24
+ 'card_expiry_date' => 'FFaker::Bank.card_expiry_date',
25
+ 'book_title' => 'FFaker::Book.title',
26
+ 'book_genre' => 'FFaker::Book.genre',
27
+ 'book_author' => 'FFaker::Book.author',
28
+ 'book_isbn' => 'FFaker::Book.isbn',
29
+ 'boolean' => 'FFaker::Boolean.maybe',
30
+ 'color' => 'FFaker::Color.name',
31
+ 'color_hex_code' => 'FFaker::Color.hex_code',
32
+ 'company_name' => 'FFaker::Company.name',
33
+ 'position' => 'FFaker::Company.position',
34
+ 'currency_code' => 'FFaker::Currency.code',
35
+ 'currency_name' => 'FFaker::Currency.name',
36
+ 'currency_symbol' => 'FFaker::Currency.symbol',
37
+ 'education_degree' => 'FFaker::Education.degree',
38
+ 'school_name' => 'FFaker::Education.school_name',
39
+ 'ingredient' => 'FFaker::Food.ingredient',
40
+ 'vegetable' => 'FFaker::Food.vegetable',
41
+ 'fruit' => 'FFaker::Food.fruit',
42
+ 'meat' => 'FFaker::Food.meat',
43
+ 'game_title' => 'FFaker::Game.title',
44
+ 'game_category' => 'FFaker::Game.category',
45
+ 'gender_binary' => 'FFaker::Gender.binary',
46
+ 'gender_random' => 'FFaker::Gender.random',
47
+ 'latitude' => 'FFaker::Geolocation.lat',
48
+ 'longitude' => 'FFaker::Geolocation.lng',
49
+ 'email' => 'FFaker::Internet.email',
50
+ 'username' => 'FFaker::Internet.user_name',
51
+ 'domain' => 'FFaker::Internet.domain_name',
52
+ 'slug' => "Faker::Internet.slug(nil, '-')",
53
+ 'job_title' => 'FFaker::Job.title',
54
+ 'locale' => 'FFaker::Locale.code',
55
+ 'language' => 'FFaker::Locale.language',
56
+ 'movie' => 'FFaker::Movie.title',
57
+ 'name' => 'FFaker::Name.name',
58
+ 'number' => 'FFaker::Number.number',
59
+ 'decimal' => 'FFaker::Number.decimal',
60
+ 'phone_number' => 'FFaker::PhoneNumber.phone_number',
61
+ 'brand_name' => 'FFaker::Product.brand',
62
+ 'product_name' => 'FFaker::Product.product_name',
63
+ 'tech_skill' => 'FFaker::Skill.tech_skill',
64
+ 'specialty' => 'FFaker::Skill.specialty',
65
+ 'sport_name' => 'FFaker::SportUS.name',
66
+ 'ssn' => 'FFaker::SSN.ssn',
67
+ 'month' => 'FFaker::Time.month',
68
+ 'datetime' => 'FFaker::Time.datetime',
69
+ 'date' => 'FFaker::Time.date'
70
+ }.freeze
71
+
72
+ def self.detect(specialized)
73
+ MAPPINGS[specialized]
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'factories/column'
4
+
5
+ module RailsFormation
6
+ module Formatters
7
+ class Factory < Thor::Group
8
+ include Thor::Actions
9
+
10
+ argument :factory_configuration
11
+ argument :factory_path
12
+
13
+ def create_factory
14
+ template('../templates/factory.rb.tt', factory_path)
15
+ end
16
+
17
+ def self.source_root
18
+ __dir__
19
+ end
20
+
21
+ private
22
+
23
+ def factory_name
24
+ factory_configuration.fetch('name')
25
+ end
26
+
27
+ def associations
28
+ []
29
+ end
30
+
31
+ def columns
32
+ factory_configuration.fetch('fields', []).map do |config|
33
+ RailsFormation::Formatters::Factories::Column.new(config).to_s
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'migrations/column'
4
+ require_relative 'migrations/index'
5
+
6
+ module RailsFormation
7
+ module Formatters
8
+ class Migration < Thor::Group
9
+ include Thor::Actions
10
+
11
+ argument :migration_configuration
12
+ argument :migration_path
13
+
14
+ def create_migration
15
+ template('../templates/migration.rb.tt', migration_path)
16
+ end
17
+
18
+ def self.source_root
19
+ __dir__
20
+ end
21
+
22
+ private
23
+
24
+ def table_name
25
+ migration_configuration.fetch('table')
26
+ end
27
+
28
+ def timestamps?
29
+ migration_configuration.fetch('timestamps', false)
30
+ end
31
+
32
+ def columns
33
+ migration_configuration.fetch('columns', []).map do |config|
34
+ RailsFormation::Formatters::Migrations::Column.new(config).to_s
35
+ end
36
+ end
37
+
38
+ def indices
39
+ migration_configuration.fetch('indices', []).map do |config|
40
+ RailsFormation::Formatters::Migrations::Index.new(table_name, config).to_s
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Migrations
6
+ class Column
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def to_s
12
+ base_definition = [
13
+ 't.',
14
+ @config.fetch('type'),
15
+ ' :',
16
+ @config.fetch('name')
17
+ ].join
18
+
19
+ return base_definition if @config['options'].nil? || @config['options'].size.zero?
20
+
21
+ options = @config['options'].map do |option|
22
+ value = option['value']
23
+ parsed_value = value.is_a?(String) ? "'#{value}'" : value
24
+
25
+ "#{option['name']}: #{parsed_value}"
26
+ end.join(', ')
27
+
28
+ [base_definition, ', ', options].join
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Migrations
6
+ class Index
7
+ def initialize(table_name, config)
8
+ @table_name = table_name
9
+ @config = config
10
+ end
11
+
12
+ def to_s
13
+ column_slug = if @config.fetch('column_names').size == 1
14
+ ":#{@config.fetch('column_names').first}"
15
+ else
16
+ "[#{@config.fetch('column_names').map { |col| ":#{col}" }.join(', ')}]"
17
+ end
18
+
19
+ base_definition = "add_index :#{@table_name}, #{column_slug}"
20
+
21
+ return base_definition if @config.fetch('options', []).size.zero?
22
+
23
+ options = @config['options'].map { |option| option.values.join(': ') }.join(', ')
24
+
25
+ "#{base_definition}, #{options}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'models/validation'
4
+
5
+ module RailsFormation
6
+ module Formatters
7
+ class Model < Thor::Group
8
+ include Thor::Actions
9
+
10
+ argument :model_configuration
11
+ argument :model_path
12
+
13
+ def create_model
14
+ template('../templates/model.rb.tt', model_path)
15
+ end
16
+
17
+ def self.source_root
18
+ __dir__
19
+ end
20
+
21
+ private
22
+
23
+ def class_name
24
+ model_configuration.fetch('name')
25
+ end
26
+
27
+ def validations
28
+ models_with_validations = model_configuration.fetch('columns', []).select do |config|
29
+ config.fetch('validations', []).size.positive?
30
+ end
31
+
32
+ models_with_validations.map do |config|
33
+ config.fetch('validations', []).map do |val_config|
34
+ ::RailsFormation::Formatters::Models::Validation.new(
35
+ val_config.merge('column' => config.fetch('name'))
36
+ ).to_s
37
+ end
38
+ end.flatten
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'validations/base'
4
+ require_relative 'validations/presence'
5
+ require_relative 'validations/uniqueness'
6
+ require_relative 'validations/length'
7
+ require_relative 'validations/inclusion'
8
+ require_relative 'validations/exclusion'
9
+ require_relative 'validations/confirmation'
10
+ require_relative 'validations/format'
11
+ require_relative 'validations/numericality'
12
+ require_relative 'validations/comparsion'
13
+
14
+ module RailsFormation
15
+ module Formatters
16
+ module Models
17
+ class Validation
18
+ MAPPINGS = {
19
+ 'presence' => ::RailsFormation::Formatters::Models::Validations::Presence,
20
+ 'uniqueness' => ::RailsFormation::Formatters::Models::Validations::Uniqueness,
21
+ 'length' => ::RailsFormation::Formatters::Models::Validations::Length,
22
+ 'inclusion' => ::RailsFormation::Formatters::Models::Validations::Inclusion,
23
+ 'exclusion' => ::RailsFormation::Formatters::Models::Validations::Exclusion,
24
+ 'confirmation' => ::RailsFormation::Formatters::Models::Validations::Confirmation,
25
+ 'format' => ::RailsFormation::Formatters::Models::Validations::Format,
26
+ 'numericality' => ::RailsFormation::Formatters::Models::Validations::Numericality,
27
+ 'comparsion' => ::RailsFormation::Formatters::Models::Validations::Comparsion
28
+ }.freeze
29
+
30
+ def initialize(config)
31
+ @config = config
32
+ end
33
+
34
+ def to_s
35
+ klass = MAPPINGS[@config.fetch('name')]
36
+ klass.new(@config).to_s
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Models
6
+ module Validations
7
+ class Base
8
+ def initialize(config)
9
+ @config = config
10
+ end
11
+
12
+ private
13
+
14
+ def allow_blank_option
15
+ return unless @config.fetch('allow_blank')
16
+
17
+ 'allow_blank: true'
18
+ end
19
+
20
+ def allow_nil_option
21
+ return unless @config.fetch('allow_nil')
22
+
23
+ 'allow_nil: true'
24
+ end
25
+
26
+ def message_option
27
+ return if @config.fetch('message').nil? || @config.fetch('message').empty?
28
+
29
+ "message: '#{@config.fetch('message')}'"
30
+ end
31
+
32
+ def on_option
33
+ return if @config.fetch('on_create') && @config.fetch('on_update')
34
+
35
+ if @config.fetch('on_create')
36
+ 'on: :create'
37
+ elsif @config.fetch('on_update')
38
+ 'on: :update'
39
+ end
40
+ end
41
+
42
+ def column_name
43
+ @config.fetch('column')
44
+ end
45
+
46
+ def base_options
47
+ [
48
+ allow_blank_option,
49
+ allow_nil_option,
50
+ message_option,
51
+ on_option
52
+ ].compact
53
+ end
54
+
55
+ def validation_options
56
+ @config.fetch('options', {})
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Models
6
+ module Validations
7
+ class Comparsion < RailsFormation::Formatters::Models::Validations::Base
8
+ def to_s
9
+ "validates :#{column_name}, comparsion: { #{extra_options.join(', ')} }"
10
+ end
11
+
12
+ private
13
+
14
+ def extra_options
15
+ base_options | extra_validation_options
16
+ end
17
+
18
+ def extra_validation_options
19
+ value = if validation_options['comparsion_value_type'] == 'column_value'
20
+ ":#{validation_options['comparsion_value']}"
21
+ else
22
+ validation_options['comparsion_value']
23
+ end
24
+
25
+ ["#{validation_options['comparsion_operator']}: #{value}"]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Models
6
+ module Validations
7
+ class Confirmation < RailsFormation::Formatters::Models::Validations::Base
8
+ def to_s
9
+ if base_options.any?
10
+ "validates :#{column_name}, confirmation: { #{base_options.join(', ')} }"
11
+ else
12
+ "validates :#{column_name}, confirmation: true"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsFormation
4
+ module Formatters
5
+ module Models
6
+ module Validations
7
+ class Exclusion < RailsFormation::Formatters::Models::Validations::Base
8
+ def to_s
9
+ "validates :#{column_name}, exclusion: { #{extra_options.join(', ')} }"
10
+ end
11
+
12
+ private
13
+
14
+ def extra_options
15
+ base_options | extra_validation_options
16
+ end
17
+
18
+ def extra_validation_options
19
+ ["in: #{validation_options['in']}"]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end