rails_zen 0.1.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.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ffdf4939e8dda4d2ca2dca549392f46b0a417a3a
|
4
|
+
data.tar.gz: 33d799f39f4be8726d9ba7b4f7da2a8b6a35acc7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d845aade057e447bb8860e6179286e9628ec4b8e3194ff59690ca08774a6d504640d109297a5d5a67f012e4719750ef1b9576a2674477cfeaf4b1e2994c7d88
|
7
|
+
data.tar.gz: 2d67d68126efc3db3158436f616e16917e1ed2b57f47fe17473eedfe946c0e62adcc7383555d6f0f4741a3e4f62c7f946498945e84ac5564e62ece24e0afb9f5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Vysakh Sreenivasan
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# RailsZen
|
2
|
+
|
3
|
+
**AIM**: To save time by giving a boilerplate, and a thought flow.
|
4
|
+
|
5
|
+
A step by step generator. This will get *uniqueness*, *validations* from you, and write
|
6
|
+
the appropriate files (model, migration, model_spec).
|
7
|
+
|
8
|
+
The specs generated here assumes you are using
|
9
|
+
|
10
|
+
- Rspec (>3.0)
|
11
|
+
- Shoulda matchers
|
12
|
+
- FactoryGirl
|
13
|
+
|
14
|
+
*NOTE*: You need to use this app at the root of your rails directory
|
15
|
+
|
16
|
+
*Disclamier*: Things like mocks, stubs and proper testing might not be possible with this project.
|
17
|
+
The aim is to automate as many things as possible, this is not a panacea :) .
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'rails_zen'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
$ gem install rails_zen
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
### COMMANDS
|
38
|
+
|
39
|
+
#### model g (generate)
|
40
|
+
|
41
|
+
rails_zen model g user name:string score:integer
|
42
|
+
|
43
|
+
- Once you enter this command, you will have few questions asked such as what to validate, which attribute is unique.
|
44
|
+
- Based on your input, the model, model_spec and migration files will be written
|
45
|
+
|
46
|
+
#### model act (action)
|
47
|
+
|
48
|
+
rails_zen model act calculator sum
|
49
|
+
|
50
|
+
- When you want to add a method to your model, you could invoke this command.
|
51
|
+
|
52
|
+
- This will get inputs from you such as:
|
53
|
+
- what the method does
|
54
|
+
- the argument names
|
55
|
+
- sample argument with a corresponding output
|
56
|
+
|
57
|
+
- Based on these input, a skeleton method will be written to your model file and model spec file
|
58
|
+
|
59
|
+
*OPTIONS*: If you want to write a class method you can pass --class option like this
|
60
|
+
|
61
|
+
|
62
|
+
rails_zen model g calculator sum --class
|
63
|
+
|
64
|
+
#### Use help to see the examples
|
65
|
+
|
66
|
+
rails_zen model g help
|
67
|
+
rails_zen model act help
|
68
|
+
|
69
|
+
You could see this sample video demonstrating the usage of the gem.
|
70
|
+
|
71
|
+
[](http://youtu.be/rXphSHFXT1M)
|
72
|
+
|
73
|
+
### Tip
|
74
|
+
|
75
|
+
- Create aliases for these commands in your bashrc or zshrc.
|
76
|
+
- I'm using
|
77
|
+
|
78
|
+
alias rzmg="rails_zen model g "
|
79
|
+
alias rzma="rails_zen model act "
|
80
|
+
|
81
|
+
```bash
|
82
|
+
rzmg user name:string score:integer
|
83
|
+
rzma user calculate_score
|
84
|
+
```
|
85
|
+
## Contributing
|
86
|
+
|
87
|
+
1. Fork it ( https://github.com/[my-github-username]/rails_zen/fork )
|
88
|
+
|
89
|
+
bundle binstub rspec-core
|
90
|
+
bundle binstub cucumber
|
91
|
+
|
92
|
+
bin/rspec
|
93
|
+
bin/cucumber
|
94
|
+
|
95
|
+
- This project uses [thor](https://github.com/erikhuda/thor/). You could [refer this blog post](willschenk.com/making-a-command-line-utility-with-gems-and-thor/) to get a quick idea.
|
96
|
+
- To read the source code, start with `lib/cli.rb` & `bin/rails_zen`
|
97
|
+
|
98
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
99
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
100
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
101
|
+
5. Please write unit test using rspec and integeration spec using aruba/cucumber.
|
102
|
+
6. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/rails_zen
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
Feature: Create a function & related spec for the model
|
2
|
+
|
3
|
+
Scenario: Enters the command with arguments
|
4
|
+
When I run `rails_zen model act calculator sum` interactively
|
5
|
+
When I close the stdin stream
|
6
|
+
Then the output should contain "What does your method do?"
|
7
|
+
|
8
|
+
Scenario: Enters what the method does
|
9
|
+
When I run `rails_zen model act calculator sum` interactively
|
10
|
+
And I type "returns sum of two numbers"
|
11
|
+
#And I type "a,b"
|
12
|
+
#And I type "1,2"
|
13
|
+
#And I type "3"
|
14
|
+
When I close the stdin stream
|
15
|
+
Then the output should contain "What name would you give your arguments"
|
16
|
+
|
17
|
+
Scenario: Enters the argument names
|
18
|
+
When I run `rails_zen model act calculator sum` interactively
|
19
|
+
And I type "returns sum of two numbers"
|
20
|
+
And I type "a,b"
|
21
|
+
#And I type "1,2"
|
22
|
+
#And I type "3"
|
23
|
+
When I close the stdin stream
|
24
|
+
Then the output should contain "Give example arguments"
|
25
|
+
|
26
|
+
Scenario: Enters the argument values
|
27
|
+
When I run `rails_zen model act calculator sum` interactively
|
28
|
+
And I type "returns sum of two numbers"
|
29
|
+
And I type "a,b"
|
30
|
+
And I type "1,2"
|
31
|
+
#And I type "3"
|
32
|
+
When I close the stdin stream
|
33
|
+
Then the output should contain "Enter the expected output for the previously entered arguments. eg: 3"
|
34
|
+
|
35
|
+
Scenario: Enters no arguments
|
36
|
+
When I run `rails_zen model act greet hello` interactively
|
37
|
+
And I type "says hello"
|
38
|
+
And I type ""
|
39
|
+
When I close the stdin stream
|
40
|
+
Then the output should not contain "Give example arguments"
|
41
|
+
|
42
|
+
#@focus
|
43
|
+
#Scenario: Enters the end result
|
44
|
+
#When I run `rails_zen model act user sum` interactively
|
45
|
+
#And I type "returns sum of two numbers"
|
46
|
+
#And I type "a,b"
|
47
|
+
#And I type "1,2"
|
48
|
+
#And I type "3"
|
49
|
+
#Then For this user model, the exit status should be 0
|
@@ -0,0 +1,64 @@
|
|
1
|
+
Feature: Generate model related things
|
2
|
+
|
3
|
+
Scenario: Enters the command with arguments
|
4
|
+
When I run `rails_zen model g user name:string` interactively
|
5
|
+
And I type "0"
|
6
|
+
When I close the stdin stream
|
7
|
+
Then the output should contain "0 name"
|
8
|
+
|
9
|
+
Scenario: Selects simple attributes
|
10
|
+
When I run `rails_zen model g user name:string phone:integer` interactively
|
11
|
+
And I type "0"
|
12
|
+
And I type "n"
|
13
|
+
When I close the stdin stream
|
14
|
+
Then the output should contain "Should :phone be present always in your record?"
|
15
|
+
|
16
|
+
Scenario: No unique attributes and integer
|
17
|
+
When I run `rails_zen model g user name:string phone:integer` interactively
|
18
|
+
And I type "0"
|
19
|
+
And I type "n"
|
20
|
+
And I type " "
|
21
|
+
When I close the stdin stream
|
22
|
+
Then the output should contain "phone is an integer do you want to check"
|
23
|
+
|
24
|
+
Scenario: No unique attributes, integer and has a relation
|
25
|
+
When I run `rails_zen model g user name:string` interactively
|
26
|
+
And I type "0"
|
27
|
+
And I type "n"
|
28
|
+
And I type "posts"
|
29
|
+
When I close the stdin stream
|
30
|
+
#Then the exit status should be 0
|
31
|
+
Then the output should contain "Do you have any has_many relations?"
|
32
|
+
|
33
|
+
#@focus
|
34
|
+
# file writing part
|
35
|
+
#Scenario: No unique attributes, integer and has a relation
|
36
|
+
#When I run `rails_zen model g user name:string phone:integer` interactively
|
37
|
+
#And I type "1"
|
38
|
+
#And I type "n"
|
39
|
+
#And I type "posts"
|
40
|
+
#Then the exit status should be 0
|
41
|
+
|
42
|
+
|
43
|
+
Scenario: No unique attributes and string
|
44
|
+
When I run `rails_zen model g user name:string phone:integer` interactively
|
45
|
+
And I type "1"
|
46
|
+
And I type "n"
|
47
|
+
And I type " "
|
48
|
+
Then the exit status should be 0
|
49
|
+
|
50
|
+
Scenario: not a unique attribute and a relation
|
51
|
+
When I run `rails_zen model g user name:string phone:integer location:belongs_to` interactively
|
52
|
+
And I type "0,1"
|
53
|
+
And I type "y"
|
54
|
+
Given I have all files
|
55
|
+
And I type "0"
|
56
|
+
Then the output should contain "0 if it is not unique"
|
57
|
+
|
58
|
+
Scenario: unique attribute is a relation
|
59
|
+
When I run `rails_zen model g user name:string phone:integer location:belongs_to` interactively
|
60
|
+
And I type "0,1"
|
61
|
+
And I type "y"
|
62
|
+
Given I have all files
|
63
|
+
And I type "1"
|
64
|
+
Then the output should contain "0 if it is not unique"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails_zen/write_to_files/write_to_model'
|
2
|
+
|
3
|
+
Then /^For this (\w+) model, the exit status should be (\d+)$/ do |model, exit_status|
|
4
|
+
#File.open("app/models/#{model}.rb", 'w+') {|f| f.write("class #{model.capitalize} < ActiveRecord::Base\nend\n") }
|
5
|
+
assert_exit_status(exit_status.to_i)
|
6
|
+
end
|
7
|
+
|
8
|
+
Given /I have all files/ do
|
9
|
+
file = String.new("class User < ActiveRecord::Base\nend\n")
|
10
|
+
loc = double('file')
|
11
|
+
|
12
|
+
allow(File).to receive(:open).with(any_args) { loc }
|
13
|
+
allow(File).to receive(:binread).with(any_args) { file }
|
14
|
+
|
15
|
+
allow_any_instance_of(RailsZen::WriteToModel).to receive(:file_name) { '/randompath/yo'}
|
16
|
+
|
17
|
+
allow(Dir).to receive(:glob).with(any_args) {["2023_create_users.rb"]}
|
18
|
+
end
|
data/lib/cli.rb
ADDED
data/lib/cli/model.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "rails_zen/given_model_gen"
|
2
|
+
require "rails_zen/model_action"
|
3
|
+
|
4
|
+
module RailsZen
|
5
|
+
module CLI
|
6
|
+
class Model < Thor
|
7
|
+
desc "g MODELNAME ATTRIBUTES", "generate model, migration, spec files and step & step validations"
|
8
|
+
long_desc %{
|
9
|
+
|
10
|
+
Eg: rails_zen g model user name:string email:string score:integer
|
11
|
+
|
12
|
+
The command generates the usual model, migration and model_spec files. After that,
|
13
|
+
things we manually add such as validation or uniqueness are interactively asked by
|
14
|
+
this command to write into model, migration and spec file.
|
15
|
+
|
16
|
+
|
17
|
+
}
|
18
|
+
def g(model_name, *attrs)
|
19
|
+
attrs = attrs.join(' ')
|
20
|
+
system("rails g model #{model_name} #{attrs}")
|
21
|
+
RailsZen::GivenModelGen.new(model_name, attrs).step_by_step
|
22
|
+
|
23
|
+
#check_has_many
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "act MODELNAME NAME ", "create an actions and action spec for a model"
|
27
|
+
option :class
|
28
|
+
def act(model_name, action_name)
|
29
|
+
RailsZen::ModelAction.new(action_name, options[:class], model_name).write!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/rails_zen.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'highline/import'
|
3
|
+
|
4
|
+
module RailsZen
|
5
|
+
class ChosenAttr
|
6
|
+
attr_accessor :name, :type, :validator, :type_based_validators, :scope_attr
|
7
|
+
|
8
|
+
def initialize(name, type)
|
9
|
+
@name = name
|
10
|
+
@type = type
|
11
|
+
@scope_attr = []
|
12
|
+
end
|
13
|
+
def get_user_inputs
|
14
|
+
get_presence_req
|
15
|
+
get_type_based_validations
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_presence_req
|
19
|
+
say "\n\nShould :#{name} be present always in your record?\n"
|
20
|
+
say"--------------------------------------------------------------"
|
21
|
+
inp = agree("Reply with y or n")
|
22
|
+
|
23
|
+
if inp
|
24
|
+
@validator = "validates_presence_of"
|
25
|
+
#say "What should be the default value? If there is no default value enter n"
|
26
|
+
#val = $stdin.gets.strip
|
27
|
+
#if val != 'n'
|
28
|
+
#@default_value = val
|
29
|
+
#end
|
30
|
+
get_uniqueness_req
|
31
|
+
else
|
32
|
+
@validator = nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_uniqueness_req
|
37
|
+
say "Should :#{name} be an unique column?\n"
|
38
|
+
say "-------------------------------------\n\n"
|
39
|
+
say "Reply with \n
|
40
|
+
0 if it is not unique \n
|
41
|
+
1 if it is just unique \n
|
42
|
+
2 if it is unique with respect to another attr \n\n"
|
43
|
+
|
44
|
+
inp = ask("Please enter", Integer) { |q| q.in = 0..2 }
|
45
|
+
|
46
|
+
if inp == 2
|
47
|
+
#say "Setting presence true in your models and migrations"
|
48
|
+
say "\n#{name} is unique along with ?\n Reply with attr name\n "
|
49
|
+
|
50
|
+
if is_relation?
|
51
|
+
@scope_attr << "#{name}_id" unless name.end_with? "_id"
|
52
|
+
end
|
53
|
+
|
54
|
+
say("if it is a relation reply along with id: eg: user_id \n\n $->")
|
55
|
+
@scope_attr << ask("Enter (comma sep list) ", lambda { |str| str.split(/,\s*/) })
|
56
|
+
@scope_attr = @scope_attr.flatten.map(&:to_sym)
|
57
|
+
|
58
|
+
@validator = "validates_uniqueness_scoped_to"
|
59
|
+
elsif inp == 1
|
60
|
+
@validator = "validates_uniqueness_of"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_type_based_validations
|
65
|
+
if(type == "integer" || type == "decimal")
|
66
|
+
@validator_line = "#@validator_line, numericality: true"
|
67
|
+
|
68
|
+
say "#{name} is an integer do you want to check \n
|
69
|
+
1 just the numericality? \n
|
70
|
+
2 check if it is only integer\n\n $->
|
71
|
+
"
|
72
|
+
input = ask("Please enter", Integer) { |q| q.in = 1..2}
|
73
|
+
|
74
|
+
map_input = {
|
75
|
+
1 => "validate_numericality", 2 => "validate_integer"
|
76
|
+
#"3" => "validate_greater_than", "4" => "validate_lesser_than"
|
77
|
+
}
|
78
|
+
|
79
|
+
@type_based_validators = map_input[input]
|
80
|
+
|
81
|
+
elsif(is_relation?)
|
82
|
+
@type_based_validators = "validate_belongs_to"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
def is_relation?
|
86
|
+
type =="belongs_to" || type == "references" || (type.end_with? "_id")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|