rails-formation 0.0.0.1

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