rails_zen 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +102 -0
- data/Rakefile +8 -0
- data/bin/rails_zen +4 -0
- data/features/model/act.feature +49 -0
- data/features/model/g.feature +64 -0
- data/features/step_definitions/mock_file_steps.rb +18 -0
- data/features/support/env.rb +9 -0
- data/lib/cli.rb +10 -0
- data/lib/cli/model.rb +33 -0
- data/lib/rails_zen.rb +5 -0
- data/lib/rails_zen/chosen_attr.rb +89 -0
- data/lib/rails_zen/given_model_gen.rb +76 -0
- data/lib/rails_zen/model_action.rb +106 -0
- data/lib/rails_zen/version.rb +3 -0
- data/lib/rails_zen/write_to_files.rb +31 -0
- data/lib/rails_zen/write_to_files/model_level_validation.rb +12 -0
- data/lib/rails_zen/write_to_files/model_level_validation_spec.rb +14 -0
- data/lib/rails_zen/write_to_files/write_to_migration.rb +37 -0
- data/lib/rails_zen/write_to_files/write_to_model.rb +57 -0
- data/lib/rails_zen/write_to_files/write_to_spec.rb +45 -0
- data/lib/railtie.rb +8 -0
- data/rails_zen.gemspec +29 -0
- data/spec/chosen_attr_spec.rb +92 -0
- data/spec/given_model_gen_spec.rb +81 -0
- data/spec/model_action_spec.rb +81 -0
- data/spec/shared/build_file_attr.rb +12 -0
- data/spec/spec_helper.rb +93 -0
- data/spec/support/aruba.rb +11 -0
- data/spec/write_to_files/write_to_migration_spec.rb +50 -0
- data/spec/write_to_files/write_to_model_spec.rb +57 -0
- data/spec/write_to_files/write_to_spec_spec.rb +63 -0
- data/spec/write_to_files_spec.rb +9 -0
- metadata +196 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rails_zen/chosen_attr'
|
2
|
+
require 'rails_zen/write_to_files'
|
3
|
+
require 'highline/import'
|
4
|
+
|
5
|
+
module RailsZen
|
6
|
+
class GivenModelGen
|
7
|
+
attr_accessor :name, :raw_attributes, :simple_attributes
|
8
|
+
|
9
|
+
def initialize(name, raw_attrs)
|
10
|
+
@name = name
|
11
|
+
@raw_attributes = raw_attrs
|
12
|
+
@simple_attributes = []
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def step_by_step
|
17
|
+
say "\nThese are your attributes"
|
18
|
+
say "---------------------------\n"
|
19
|
+
|
20
|
+
attrs.each_with_index { |attr, i| puts "#{i} #{attr}" }
|
21
|
+
say "\n\nChoose the one that don't require 'presence true' or 'validations' or uniqueness.\n Enter like this eg: 0,1. or just enter "
|
22
|
+
say "\n----------------------------------\n\n$.> "
|
23
|
+
|
24
|
+
@simple_attributes = ask("Enter (comma sep list) ", lambda { |str| str.split(/,\s*/) })
|
25
|
+
|
26
|
+
chosen_attrs.each do |attr_obj|
|
27
|
+
attr_obj.get_user_inputs
|
28
|
+
RailsZen::WriteToFiles.new(attr_obj, name).write
|
29
|
+
end
|
30
|
+
|
31
|
+
ask_for_has_many_relations
|
32
|
+
end
|
33
|
+
|
34
|
+
def chosen_attrs
|
35
|
+
|
36
|
+
attr_hash = attrs_with_types
|
37
|
+
final_attr_objs = []
|
38
|
+
i = -1
|
39
|
+
attr_hash.each do |attr, type|
|
40
|
+
i += 1
|
41
|
+
unless simple_attributes.include? "#{i}"
|
42
|
+
final_attr_objs << RailsZen::ChosenAttr.new(attr, type)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
final_attr_objs
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def ask_for_has_many_relations
|
50
|
+
say "\nDo you have any has_many relations? Enter the name if so, otherwise leave it. eg: posts,comments"
|
51
|
+
|
52
|
+
@has_many_relations = ask("Enter (comma sep list) ", lambda { |str| str.split(/,\s*/) })
|
53
|
+
|
54
|
+
@has_many_relations.each do |rel|
|
55
|
+
|
56
|
+
m = RailsZen::WriteToModel.new
|
57
|
+
m.model_name = @name
|
58
|
+
m.adding_to_file!(" has_many :#{rel}\n")
|
59
|
+
|
60
|
+
s = RailsZen::WriteToSpec.new
|
61
|
+
s.model_name = @name
|
62
|
+
s.adding_to_file!("it { is_expected.to have_many(:#{rel}) }")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
def attrs
|
67
|
+
raw_attributes.scan(/\w+(?=:)/)
|
68
|
+
end
|
69
|
+
private
|
70
|
+
def attrs_with_types
|
71
|
+
raw_attributes.scan(/(\w+):(\w+)/).to_h
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rails_zen/write_to_files/write_to_model'
|
2
|
+
require 'rails_zen/write_to_files/write_to_spec'
|
3
|
+
require 'highline/import'
|
4
|
+
|
5
|
+
module RailsZen
|
6
|
+
class ModelAction
|
7
|
+
attr_writer :is_class_action
|
8
|
+
|
9
|
+
def initialize(name, is_class_action, model)
|
10
|
+
@name = name
|
11
|
+
@model = model
|
12
|
+
@is_class_action = is_class_action
|
13
|
+
@arg_names = []
|
14
|
+
@args = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def write!
|
18
|
+
get_necessary_info
|
19
|
+
|
20
|
+
m = RailsZen::WriteToModel.new
|
21
|
+
m.model_name = @model
|
22
|
+
m.adding_to_file!(action_string)
|
23
|
+
|
24
|
+
s = RailsZen::WriteToSpec.new
|
25
|
+
s.model_name = @model
|
26
|
+
|
27
|
+
unless File.foreach("spec/models/#{@model}_spec.rb").grep(factory_girl_match).any? #check for factory
|
28
|
+
s.adding_to_file!(factory_method)
|
29
|
+
end
|
30
|
+
s.adding_to_file!(action_spec_string)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def factory_girl_match
|
36
|
+
Regexp.new("FactoryGirl.create(:#{@model})")
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_necessary_info
|
40
|
+
say "What does your method do? (Please don't use 'it' or 'should' in your definition)\n"
|
41
|
+
@functionality = ask("Eg: returns sum of 2 numbers\n")
|
42
|
+
|
43
|
+
say "\n\n------------ARGUMENTS-----------------\n"
|
44
|
+
|
45
|
+
say "\nWhat name would you give your arguments for the #{@name} method? eg: num1,num2\n"
|
46
|
+
|
47
|
+
@arg_names = ask("Enter (comma sep) list", lambda { |str| str.split(/,\s*/) })
|
48
|
+
|
49
|
+
if @arg_names.any?
|
50
|
+
say "\nGive example arguments inputs\n"
|
51
|
+
@args = ask("Enter (comma sep list). Eg: 1,2 ", lambda { |str| str.split(/,\s*/) })
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
@expected = ask("Enter the expected output for the previously entered arguments. eg: 3")
|
56
|
+
end
|
57
|
+
|
58
|
+
def action_string
|
59
|
+
%{
|
60
|
+
def #{method_with_args}
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def action_spec_string
|
66
|
+
if @is_class_action
|
67
|
+
%{
|
68
|
+
it { is_expected.to respond_to :#{@name}}
|
69
|
+
|
70
|
+
describe ".#{@name}" do
|
71
|
+
it "#{@functionality}" do
|
72
|
+
expect(#{@model.capitalize}.#{@name}(#{sample_arguments})).to eq \"#{@expected}\"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
}
|
77
|
+
else
|
78
|
+
%{
|
79
|
+
describe "##{@name}" do
|
80
|
+
it "#{@functionality}" do
|
81
|
+
expect(#{@model}.#{@name}(#{sample_arguments})).to eq \"#{@expected}\"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
def method_with_args
|
89
|
+
if @is_class_action
|
90
|
+
"self.#{@name}(#{arguments})"
|
91
|
+
else
|
92
|
+
"#{@name}(#{arguments})"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def sample_arguments
|
97
|
+
@args.join(", ")
|
98
|
+
end
|
99
|
+
def arguments
|
100
|
+
@arg_names.join(", ")
|
101
|
+
end
|
102
|
+
def factory_method
|
103
|
+
"let(:#{@model}) { FactoryGirl.create(:#{@model}) }"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rails_zen/write_to_files/write_to_spec'
|
2
|
+
require 'rails_zen/write_to_files/write_to_model'
|
3
|
+
require 'rails_zen/write_to_files/write_to_migration'
|
4
|
+
|
5
|
+
class RailsZen::WriteToFiles
|
6
|
+
attr_reader :attr, :model_name
|
7
|
+
|
8
|
+
def initialize(attr, model_name)
|
9
|
+
@attr = attr
|
10
|
+
@model_name = model_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_file_writers(type)
|
14
|
+
# When including thor, could not use initialize hence building it
|
15
|
+
Object.const_get("RailsZen::#{type}").new.tap do |w|
|
16
|
+
w.name = attr.name
|
17
|
+
w.attr_type = attr.type
|
18
|
+
w.scope_attr = attr.scope_attr
|
19
|
+
w.validator = attr.validator
|
20
|
+
w.type_based_validators = attr.type_based_validators
|
21
|
+
w.model_name = model_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def write
|
26
|
+
["WriteToSpec", "WriteToMigration", "WriteToModel"].each do |type|
|
27
|
+
build_file_writers(type).write!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RailsZen::ModelLeveLValidationSpec
|
2
|
+
|
3
|
+
def validate_belongs_to
|
4
|
+
"it { is_expected.to belong_to(:#{name}) }"
|
5
|
+
end
|
6
|
+
def validate_numericality
|
7
|
+
"it { is_expected.to validates_numericality_of(:#{name}) }"
|
8
|
+
end
|
9
|
+
def validate_integer
|
10
|
+
"it { is_expected.to validates_numericality_of(:#{name}).only_integer }"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "rails_zen/write_to_files/write_to_model"
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
|
4
|
+
class RailsZen::WriteToMigration < RailsZen::WriteToModel
|
5
|
+
|
6
|
+
def write!
|
7
|
+
if @validator
|
8
|
+
line = send(@validator)
|
9
|
+
append_to_line(line)
|
10
|
+
end
|
11
|
+
if scope_attr.any?
|
12
|
+
inject_into_file file_name, "t.index #{scope_attr.to_s}\n", before: "t.timestamps"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def append_to_line(line)
|
16
|
+
gsub_file file_name, /t.#{attr_type}.+#{name}.*$/ do |match|
|
17
|
+
match = line
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def file_name
|
22
|
+
Dir.glob("db/migrate/*create_#{@model_name.pluralize}.rb")[0]
|
23
|
+
# need to use pluralize here
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def validates_presence_of
|
28
|
+
"t.#{attr_type} :#{name}, required: true, null: false"
|
29
|
+
end
|
30
|
+
def validates_uniqueness_of
|
31
|
+
"t.#{attr_type} :#{name}, required: true, null: false, index: true"
|
32
|
+
end
|
33
|
+
def validates_uniqueness_scoped_to
|
34
|
+
"t.#{attr_type} :#{name}, required: true, null: false, index: true"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require "rails_zen/write_to_files/model_level_validation"
|
3
|
+
|
4
|
+
module RailsZen
|
5
|
+
class WriteToModel
|
6
|
+
|
7
|
+
|
8
|
+
attr_accessor :name, :scope_attr, :validator, :type_based_validators, :model_name, :attr_type, :file_name
|
9
|
+
include RailsZen::ModelLeveLValidation
|
10
|
+
include Thor::Base
|
11
|
+
include Thor::Actions
|
12
|
+
|
13
|
+
|
14
|
+
def write!
|
15
|
+
|
16
|
+
if @validator
|
17
|
+
output = send(@validator)
|
18
|
+
if type_num?
|
19
|
+
type_output = send(@type_based_validators)
|
20
|
+
adding_to_file!(" #{output + type_output}\n" )
|
21
|
+
else
|
22
|
+
adding_to_file!(" #{output}\n")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def adding_to_file!(line)
|
28
|
+
inject_into_class(file_name, model_name.capitalize, line)
|
29
|
+
end
|
30
|
+
|
31
|
+
def file_name
|
32
|
+
"app/models/#{model_name}.rb"
|
33
|
+
end
|
34
|
+
private
|
35
|
+
|
36
|
+
def type_num?
|
37
|
+
@attr_type == "integer" || @attr_type == "decimal"
|
38
|
+
end
|
39
|
+
def validates_presence_of
|
40
|
+
"validates :#{name}, presence: true"
|
41
|
+
end
|
42
|
+
def validates_uniqueness_of
|
43
|
+
"validates :#{name}, presence: true, uniqueness: true"
|
44
|
+
end
|
45
|
+
def validates_uniqueness_scoped_to
|
46
|
+
"validates_uniqueness_of :#{scope_attr[0]}, scope: #{resolve_scope}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def resolve_scope
|
50
|
+
if scope_attr.length == 2
|
51
|
+
":#{scope_attr[1]}"
|
52
|
+
else
|
53
|
+
scope_attr[1..-1].to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "rails_zen/write_to_files/model_level_validation_spec"
|
2
|
+
require "rails_zen/write_to_files/write_to_model"
|
3
|
+
|
4
|
+
class RailsZen::WriteToSpec < RailsZen::WriteToModel
|
5
|
+
|
6
|
+
include RailsZen::ModelLeveLValidationSpec
|
7
|
+
|
8
|
+
def write!
|
9
|
+
if @validator
|
10
|
+
unless File.foreach("spec/models/#{@model_name}_spec.rb").grep(factory_girl_match).any?
|
11
|
+
adding_to_file!(factory_method)
|
12
|
+
end
|
13
|
+
adding_to_file!(send(@validator))
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
adding_to_file!(send(@type_based_validator)) if @type_based_validator
|
18
|
+
end
|
19
|
+
def adding_to_file!(output)
|
20
|
+
inject_into_file(file_name, " #{output}\n", after: "RSpec.describe #{@model_name.capitalize}, type: :model do\n" )
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def factory_girl_match
|
25
|
+
Regexp.new("FactoryGirl.create(:#{@model_name})")
|
26
|
+
end
|
27
|
+
def factory_method
|
28
|
+
"let(:#{@model_name}) { FactoryGirl.create(:#{@model_name}) }"
|
29
|
+
end
|
30
|
+
|
31
|
+
def file_name
|
32
|
+
"spec/models/#{@model_name}_spec.rb"
|
33
|
+
end
|
34
|
+
|
35
|
+
def validates_presence_of
|
36
|
+
"it { #{@model_name}; is_expected.to validate_presence_of(:#{name})}"
|
37
|
+
end
|
38
|
+
def validates_uniqueness_of
|
39
|
+
"it { #{@model_name}; is_expected.to validate_uniqueness_of(:#{name})}"
|
40
|
+
end
|
41
|
+
def validates_uniqueness_scoped_to
|
42
|
+
"it { #{@model_name}; is_expected.to validate_uniqueness_of(:#{scope_attr[0]}).scoped_to(#{resolve_scope})}"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/railtie.rb
ADDED
data/rails_zen.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rails_zen/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rails_zen"
|
8
|
+
spec.version = RailsZen::VERSION
|
9
|
+
spec.authors = ["Vysakh Sreenivasan"]
|
10
|
+
spec.email = ["diplomatv@gmail.com"]
|
11
|
+
spec.summary = %q{Interactive rails generator generating files (models, migration) and related specs.}
|
12
|
+
spec.description = %q{Automate the writing of validations, relations in files and specs. Create boilerplate validation in models, specs, migrations. This specs are generated based on rspec, shoulda-matchers and factorygirl }
|
13
|
+
spec.homepage = "http://github.com/vysakh0/rails_zen"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'thor', "~> 0.19"
|
22
|
+
spec.add_dependency 'highline', "~> 1.4"
|
23
|
+
spec.add_dependency 'activesupport', "~> 4.2"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
26
|
+
spec.add_development_dependency "aruba", "~> 0.6"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
29
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'rails_zen/chosen_attr'
|
2
|
+
|
3
|
+
RSpec.describe RailsZen::ChosenAttr do
|
4
|
+
|
5
|
+
|
6
|
+
subject {
|
7
|
+
RailsZen::ChosenAttr.new("name", "string")
|
8
|
+
}
|
9
|
+
|
10
|
+
#after do
|
11
|
+
#$stdin = STDIN
|
12
|
+
#end
|
13
|
+
|
14
|
+
it { is_expected.to respond_to :get_user_inputs}
|
15
|
+
|
16
|
+
|
17
|
+
describe "#get_presence_req" do
|
18
|
+
|
19
|
+
context "when 'y' for presence" do
|
20
|
+
|
21
|
+
context "when 0 for uniqueness" do
|
22
|
+
it "sets validator to validates_presence_of" do
|
23
|
+
set_stream(StringIO.new("y\n0\n"))
|
24
|
+
subject.get_user_inputs
|
25
|
+
expect(subject.validator).to eq "validates_presence_of"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
context "when '1' for uniqueness" do
|
29
|
+
it "sets validator to validates_uniqueness_of" do
|
30
|
+
set_stream(StringIO.new("y\nr\n1\n"))
|
31
|
+
subject.get_user_inputs
|
32
|
+
expect(subject.validator).to eq "validates_uniqueness_of"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
context "when '2' for uniqueness" do
|
36
|
+
it "sets validator to validates_uniqueness_scoped_to" do
|
37
|
+
set_stream(StringIO.new("y\n 2\n order_id\n"))
|
38
|
+
subject.get_user_inputs
|
39
|
+
expect(subject.validator).to eq "validates_uniqueness_scoped_to"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
context "when n for presence" do
|
44
|
+
|
45
|
+
fit "sets validator to validates_presence_of" do
|
46
|
+
set_stream(StringIO.new("n\n"))
|
47
|
+
subject.get_user_inputs
|
48
|
+
expect(subject.validator).to be nil
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#get_type_based_validations" do
|
54
|
+
context "when type is integer" do
|
55
|
+
|
56
|
+
before do
|
57
|
+
@chosen = RailsZen::ChosenAttr.new("phone", "integer")
|
58
|
+
end
|
59
|
+
context "when just the numericality is chosen" do
|
60
|
+
fit "sets type_based_validators to validate_numericality" do
|
61
|
+
set_stream(StringIO.new("1\n"))
|
62
|
+
@chosen.get_type_based_validations
|
63
|
+
expect(@chosen.type_based_validators).to eq "validate_numericality"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
context "when numericality with integer is chosen" do
|
67
|
+
it "sets type_based_validators to validate_integer" do
|
68
|
+
set_stream(StringIO.new("2\n"))
|
69
|
+
@chosen.get_type_based_validations
|
70
|
+
expect(@chosen.type_based_validators).to eq "validate_integer"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
context "when type is a relation" do
|
75
|
+
before do
|
76
|
+
@chosen = RailsZen::ChosenAttr.new("user", "belongs_to")
|
77
|
+
end
|
78
|
+
it "sets type_based_validators to validate_belongs_to" do
|
79
|
+
@chosen.get_type_based_validations
|
80
|
+
expect(@chosen.type_based_validators).to eq "validate_belongs_to"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_stream(input)
|
88
|
+
#inp = $terminal.instance_variable_get(:@input)
|
89
|
+
#inp.flush
|
90
|
+
$terminal.instance_variable_set(:@input, input)
|
91
|
+
# highline set input, $stdin setting is not working. i.e $stdin = input
|
92
|
+
end
|