ez 0.9.1 → 0.9.5
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 +4 -4
- data/README.md +124 -18
- data/lib/ez.rb +2 -1
- data/lib/ez/controller.rb +8 -16
- data/lib/ez/dispatcher.rb +25 -25
- data/lib/ez/domain_modeler.rb +98 -25
- data/lib/ez/mapper.rb +20 -20
- data/lib/ez/model.rb +18 -0
- data/lib/ez/schema_modifier.rb +32 -25
- data/lib/ez/version.rb +1 -1
- data/lib/tasks/ez_tasks.rake +16 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cf4b1d3d88ed176c6158aa4a3d36bcf9839f7a6
|
4
|
+
data.tar.gz: c883f390a67350f0eff832ae33c8d309ad50d24a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2504acb195bd45a35c4119049e5f289a345da9dfffb8add1ce47ca4ac0ed512bd9c8d619a50b92c7352ebac8a270e02f653ede15ac0d3792686c33b759e3591b
|
7
|
+
data.tar.gz: 6c5b356cf56615a97e2bba4221a2c7e2ecc07587117642fba3fad44ed45ad3e4d5f61b5314d5c78a0963a296119174139b917278b6c576059edf0d7d85b1960d
|
data/README.md
CHANGED
@@ -1,41 +1,147 @@
|
|
1
1
|
# EZ
|
2
2
|
|
3
|
-
|
3
|
+
**Version 0.9.8**
|
4
|
+
|
5
|
+
For educational purposes only, but I'm now using it on small production apps with no problems. Would love to get more real-world feedback.
|
6
|
+
|
7
|
+
Makes domain modeling in Rails more beginner-friendly by avoiding migrations.
|
4
8
|
|
5
9
|
## Usage
|
6
10
|
|
7
11
|
```ruby
|
8
|
-
gem 'ez'
|
12
|
+
gem 'ez'
|
9
13
|
```
|
10
14
|
|
11
15
|
## Features
|
12
16
|
|
13
|
-
### 1. Console Enhancements
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
*
|
18
|
-
*
|
18
|
+
### 1. Domain Modeling Enhancements
|
19
|
+
|
20
|
+
* Enables **instant domain modeling without migrations** by editing a simple file named `db/models.yml` and then running `rake db:migrate`. If things ever get messed up, use `rake ez:reset_tables` to drop the entire db first.
|
21
|
+
* You can run `rake ez:tables` once to generate a file named `db/models.yml`. It will have some self-documenting comments inside of it.
|
22
|
+
* In development mode, there's no need to ever run `rake db:migrate` - every action will trigger automatic table updates.
|
23
|
+
* You can run `rake db:migrate` whenever you modify `db/models.yml` instead of waiting for a browser action.
|
24
|
+
|
25
|
+
**Syntax Guide for `db/models.yml`**
|
26
|
+
|
27
|
+
It's just YAML and the syntax is very simple:
|
28
|
+
|
29
|
+
```
|
30
|
+
Book:
|
31
|
+
title: string
|
32
|
+
copies_on_hand: integer
|
33
|
+
author_id: integer
|
34
|
+
created_at: datetime
|
35
|
+
updated_at: datetime
|
36
|
+
paperback: boolean
|
37
|
+
|
38
|
+
Author:
|
39
|
+
last_name: string
|
40
|
+
first_name: string
|
41
|
+
book_count: integer
|
42
|
+
```
|
19
43
|
|
20
|
-
|
44
|
+
**(Optional) Variations**
|
21
45
|
|
22
|
-
|
46
|
+
The colon after the model name is optional.
|
23
47
|
|
24
|
-
|
48
|
+
Also, you can often omit the column type and rely on conventions. I don't recommend this for beginning students, but is very handy for experienced developers. Rails conventions are embraced in `db/models.yml` resulting in these sensible defaults:
|
25
49
|
|
26
|
-
*
|
27
|
-
*
|
28
|
-
* Columns default to type `string` if none is provided and the column name doesn't have a recognized suffix.
|
29
|
-
* Column names ending in `_id` are assumed to be of type `integer`.
|
50
|
+
* If a column type isn't specified, it's assumed to be a `string` column.
|
51
|
+
* Column names ending in `_id` and `_count` are assumed to be of type `integer`.
|
30
52
|
* Column names ending in `_at` are assumed to be of type `datetime`.
|
31
53
|
* Column names ending in `_on` are assumed to be of type `date`.
|
32
|
-
|
33
|
-
|
54
|
+
|
55
|
+
Also, note that `_id` columns are further assumed to be foreign keys and will **automatically generate a database index for that column**.
|
56
|
+
|
57
|
+
So the above models could be written as:
|
58
|
+
|
59
|
+
```
|
60
|
+
Book
|
61
|
+
title
|
62
|
+
copies_on_hand: integer
|
63
|
+
author_id
|
64
|
+
created_at
|
65
|
+
updated_at
|
66
|
+
paperback: boolean
|
67
|
+
|
68
|
+
Author
|
69
|
+
last_name
|
70
|
+
first_name
|
71
|
+
book_count
|
72
|
+
```
|
73
|
+
|
74
|
+
Finally, you can specify default values for columns in several ways. Suppose we want to make sure that `copies_on_hand` always has the value `0` for new rows. First, the fancy way:
|
75
|
+
|
76
|
+
```
|
77
|
+
Book
|
78
|
+
title
|
79
|
+
copies_on_hand: integer, default: 0
|
80
|
+
author_id
|
81
|
+
created_at
|
82
|
+
updated_at
|
83
|
+
paperback: boolean
|
84
|
+
|
85
|
+
Author
|
86
|
+
last_name
|
87
|
+
first_name
|
88
|
+
book_count: integer, default: 0
|
89
|
+
```
|
90
|
+
|
91
|
+
The syntax is forgiving, so the comma and colon are just for readability; this would work too:
|
92
|
+
|
93
|
+
```
|
94
|
+
Book
|
95
|
+
title
|
96
|
+
copies_on_hand: integer default 0
|
97
|
+
author_id
|
98
|
+
created_at
|
99
|
+
updated_at
|
100
|
+
paperback: boolean
|
101
|
+
|
102
|
+
Author
|
103
|
+
last_name
|
104
|
+
first_name
|
105
|
+
book_count: integer default 0
|
106
|
+
```
|
107
|
+
|
108
|
+
And for the extra lazy like me, you can use parentheses:
|
109
|
+
|
110
|
+
```
|
111
|
+
Book
|
112
|
+
title
|
113
|
+
copies_on_hand: integer(0)
|
114
|
+
author_id
|
115
|
+
created_at
|
116
|
+
updated_at
|
117
|
+
paperback: boolean
|
118
|
+
|
119
|
+
Author
|
120
|
+
last_name
|
121
|
+
first_name
|
122
|
+
book_count(0)
|
123
|
+
```
|
124
|
+
|
125
|
+
* Boolean columns are assumed to be given a default of `false` if not otherwise specified.
|
126
|
+
|
127
|
+
|
128
|
+
### 2. More Model Enhancements
|
129
|
+
|
130
|
+
* Adds ActiveRecord::Base `.read` method so that models have complete *CRUD*: `.create`, `.read`, `.update`, and `.delete`. When given an integer, `.read` becomes a synonym for `.find`. When given a hash, it is a synonym for `.where`.
|
34
131
|
* Adds ActiveRecord::Base `.sample` method to choose a random row.
|
132
|
+
* Adds ActiveRecord::Base `[id]` method as a synonym for `.find_by(id: ...)`. Especially handy in the console, i.e. `Book[5]` instead of `Book.find_by(id: 5)` and in controllers: `Book[params[:id]]` if you don't find the double bracing too harsh to look at.
|
133
|
+
|
134
|
+
|
135
|
+
### 3. Beginner-friendly "It Just Works" console
|
136
|
+
|
137
|
+
* Solves the "no connection" message in Rails >= 4.0.1 (if you try to inspect a model without making a query first) by establishing an initial connection to the development database.
|
138
|
+
* Shows helpful instructions when console starts, including the list of model classes found in the application.
|
139
|
+
* Uses Hirb for table-like display. (Requires Hirb ~> 0.7.1)
|
140
|
+
* Patches Hirb to allow nice table output for `ActiveRecord::Relation` lists (i.e. result of `.all`, `.where`) and hash-like output for single ActiveRecord objects, such as the result of `.find_by(:title => 'Apollo 13')`.
|
141
|
+
|
35
142
|
|
36
143
|
### 4. Controller and View Enhancements
|
37
144
|
|
38
145
|
* Easier JSON API calls by calling `EZ.from_api(url)`; returns parsed Ruby hash (or array, etc.)
|
39
146
|
* Built-in view helper `<%= weather %>` and `EZ.weather` for classroom demo of a JSON API, to get quick hash and avoid gory details. (Relies on http://openweathermap.org). Default location is Evanston. Can pass location: `<%= weather('San Diego, CA') %>`. The `<%= weather %>` helper just delegates to `EZ.weather`.
|
40
|
-
* Adds
|
41
|
-
* Adds view helper `map` to display a quick static map of any address. Example: `<%= map('Millenium Park, Chicago, IL') %>`
|
147
|
+
* Adds view helper `map` to display a static Google map of any address. Example: `<%= map('Millenium Park, Chicago, IL') %>`
|
data/lib/ez.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "ez/version"
|
2
2
|
# require 'ez/dispatcher.rb'
|
3
3
|
# require 'ez/mapper.rb'
|
4
|
-
|
4
|
+
require 'ez/controller.rb'
|
5
5
|
|
6
6
|
require 'ez/apis.rb'
|
7
7
|
require 'ez/domain_modeler.rb'
|
@@ -14,6 +14,7 @@ module EZ
|
|
14
14
|
class Railtie < Rails::Railtie
|
15
15
|
rake_tasks do
|
16
16
|
load "tasks/ez_tasks.rake"
|
17
|
+
Rake::Task["db:migrate"].enhance ["ez:tables"]
|
17
18
|
end
|
18
19
|
|
19
20
|
console do |app|
|
data/lib/ez/controller.rb
CHANGED
@@ -1,25 +1,17 @@
|
|
1
1
|
module ActionController
|
2
2
|
class Base
|
3
3
|
|
4
|
-
|
5
|
-
helper_method :user_signed_in?
|
4
|
+
if Rails.env.development?
|
6
5
|
|
7
|
-
|
8
|
-
session[:user_id].present?
|
9
|
-
end
|
10
|
-
|
11
|
-
def sign_in_as(user)
|
12
|
-
@current_user = user
|
13
|
-
session[:user_id] = user.try(:id)
|
14
|
-
user
|
15
|
-
end
|
6
|
+
before_action :ez_update_tables
|
16
7
|
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
def ez_update_tables
|
9
|
+
Rails.cache.fetch('ez-generate-yml') do
|
10
|
+
EZ::DomainModeler.generate_models_yml
|
11
|
+
end
|
12
|
+
EZ::DomainModeler.update_tables
|
13
|
+
end
|
20
14
|
|
21
|
-
def current_user(klass = User)
|
22
|
-
@current_user ||= klass.send(:find_by, id: session[:user_id])
|
23
15
|
end
|
24
16
|
|
25
17
|
end
|
data/lib/ez/dispatcher.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
# require_relative './jeff_controller.rb'
|
2
2
|
|
3
|
-
module ActionDispatch
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
# module ActionDispatch
|
4
|
+
# module Routing
|
5
|
+
# class RouteSet
|
6
|
+
# class Dispatcher
|
7
|
+
# def controller(params, default_controller=true)
|
8
|
+
# if params && params.key?(:controller)
|
9
|
+
# controller_param = params[:controller]
|
10
|
+
# controller_reference(controller_param)
|
11
|
+
# end
|
12
|
+
# rescue NameError => e
|
13
|
+
# raise ActionController::RoutingError, e.message, e.backtrace if default_controller
|
14
|
+
# end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
16
|
+
# def controller_reference(controller_param)
|
17
|
+
# begin
|
18
|
+
# const_name = @controller_class_names[controller_param] ||= "#{controller_param.camelize}Controller"
|
19
|
+
# ActiveSupport::Dependencies.constantize(const_name)
|
20
|
+
# rescue NameError => e
|
21
|
+
# Kernel.class_eval("class ::#{const_name} < ApplicationController; end")
|
22
|
+
# ActiveSupport::Dependencies.constantize("::#{const_name}")
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
# end
|
data/lib/ez/domain_modeler.rb
CHANGED
@@ -3,44 +3,117 @@ require_relative 'schema_modifier'
|
|
3
3
|
module EZ
|
4
4
|
class DomainModeler
|
5
5
|
|
6
|
+
DEFAULT_VALUE_REGEXES = [/\s*\((.+)?\)/, /\s+(.+)?\s*/, /,\s*default:\s*(.+)?\s*/]
|
7
|
+
|
8
|
+
attr_reader :spec
|
9
|
+
|
6
10
|
def initialize
|
7
|
-
|
11
|
+
begin
|
12
|
+
load_model_specs
|
13
|
+
rescue => e
|
14
|
+
puts e
|
15
|
+
end
|
8
16
|
end
|
9
17
|
|
10
|
-
def self.
|
11
|
-
|
18
|
+
def self.generate_models_yml
|
19
|
+
filename = Rails.root + "db/models.yml"
|
20
|
+
unless File.exist?(filename)
|
21
|
+
File.open(filename, "w") do |f|
|
22
|
+
f.puts <<-EOS
|
23
|
+
# Example table for a typical Book model.
|
24
|
+
#
|
25
|
+
Book
|
26
|
+
title: string
|
27
|
+
price: integer
|
28
|
+
author: string
|
29
|
+
summary: text
|
30
|
+
hardcover: boolean
|
31
|
+
#
|
32
|
+
# Indent consistently! Follow the above syntax exactly.
|
33
|
+
# Typical column choices are: string, text, integer, boolean, date, and datetime.
|
34
|
+
#
|
35
|
+
# Default column values can be specified like this:
|
36
|
+
# price: integer(0)
|
37
|
+
#
|
38
|
+
# Have fun!
|
39
|
+
|
40
|
+
EOS
|
41
|
+
end
|
42
|
+
end
|
12
43
|
end
|
13
44
|
|
14
|
-
def update_tables
|
15
|
-
|
45
|
+
def self.update_tables(silent = false)
|
46
|
+
self.new.update_tables(silent)
|
16
47
|
end
|
17
48
|
|
18
|
-
def
|
19
|
-
@spec
|
20
|
-
|
49
|
+
def update_tables(silent = false)
|
50
|
+
SchemaModifier.migrate(@spec, silent)
|
51
|
+
|
52
|
+
rescue => e
|
53
|
+
puts e.message unless silent
|
54
|
+
puts e.backtrace.first unless silent
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_model_specs_from_string(s)
|
58
|
+
|
59
|
+
# Append missing colons
|
60
|
+
s.gsub!(/^((\s|\-)*\w[^\:]+?)$/, '\1:')
|
61
|
+
|
62
|
+
# Replace ", default:" syntax so YAML doesn't try to parse it
|
63
|
+
s.gsub!(/,?\s*(default)?:?\s(\S)\s*$/, '(\2)')
|
64
|
+
|
65
|
+
# For backward compatibility with old array syntax
|
66
|
+
s.gsub!(/^(\s*)\-\s*/, '\1')
|
67
|
+
|
68
|
+
@spec = YAML.load(s)
|
69
|
+
parse_model_spec
|
21
70
|
|
71
|
+
# puts "@spec:"
|
72
|
+
# puts @spec.inspect
|
73
|
+
# puts "-" * 10
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_model_specs(filename = "db/models.yml")
|
77
|
+
load_model_specs_from_string(IO.read(filename))
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_model_spec
|
81
|
+
@spec ||= {}
|
22
82
|
@spec.each do |model, columns|
|
23
|
-
|
24
|
-
columns.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
elsif column.to_s =~ /_on$/
|
31
|
-
@spec[model] << { column.to_s => 'date' }
|
32
|
-
else
|
33
|
-
@spec[model] << { column.to_s => 'string' }
|
34
|
-
end
|
35
|
-
elsif column.is_a?(Hash) && column.keys.count == 1
|
36
|
-
@spec[model] << { column.keys.first.to_s => column.values.first.to_s }
|
37
|
-
else
|
38
|
-
raise "Bad syntax around `#{column.inspect}`"
|
39
|
-
end
|
83
|
+
|
84
|
+
if !columns.is_a?(Hash)
|
85
|
+
raise "Could not understand models.yml while parsing model: #{model}"
|
86
|
+
end
|
87
|
+
|
88
|
+
columns.each do |column_name, column_type|
|
89
|
+
interpret_column_spec column_name, column_type, model
|
40
90
|
end
|
41
91
|
end
|
92
|
+
|
42
93
|
end
|
43
94
|
|
95
|
+
def interpret_column_spec(column_name, column_type, model)
|
96
|
+
column_type ||= begin
|
97
|
+
if column_name =~ /_id|_count$/
|
98
|
+
'integer'
|
99
|
+
elsif column_name =~ /_at$/
|
100
|
+
'datetime'
|
101
|
+
elsif column_name =~ /_on$/
|
102
|
+
'date'
|
103
|
+
elsif column_name =~ /\?$/
|
104
|
+
'boolean'
|
105
|
+
else
|
106
|
+
'string'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
default_column_value = (column_type == 'boolean' ? true : nil)
|
111
|
+
DEFAULT_VALUE_REGEXES.each { |r| default_column_value = $1 if column_type.sub!(r, '') }
|
112
|
+
default_column_value = default_column_value.to_i if column_type == 'integer'
|
113
|
+
default_column_value = default_column_value.to_f if column_type == 'float'
|
114
|
+
|
115
|
+
@spec[model][column_name] = { type: column_type, default: default_column_value}
|
116
|
+
end
|
44
117
|
end
|
45
118
|
|
46
119
|
end
|
data/lib/ez/mapper.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
module ActionDispatch
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# module ActionDispatch
|
2
|
+
# module Routing
|
3
|
+
# class Mapper
|
4
|
+
# class Mapping
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
# def route_uses_slash_and_no_hash?
|
7
|
+
# @options[:to].is_a?(String) &&
|
8
|
+
# @options[:to].index('#').nil? &&
|
9
|
+
# @options[:to].index('/')
|
10
|
+
# end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
12
|
+
# def to
|
13
|
+
# if route_uses_slash_and_no_hash?
|
14
|
+
# @options[:to].sub('/','#')
|
15
|
+
# else
|
16
|
+
# @options[:to]
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
data/lib/ez/model.rb
CHANGED
@@ -32,4 +32,22 @@ class ActiveRecord::Base
|
|
32
32
|
offset(rand(0...count)).first
|
33
33
|
end
|
34
34
|
|
35
|
+
def self.none?
|
36
|
+
self.count == 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.to_ez
|
40
|
+
s = self.name + ":\n"
|
41
|
+
columns.each do |column|
|
42
|
+
s << " - #{column.name}: #{column.type}\n" unless column.name == 'id'
|
43
|
+
end
|
44
|
+
s
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.dump_tables_to_ez
|
48
|
+
(connection.tables - ['schema_migrations']).each do |table|
|
49
|
+
puts table.classify.constantize.to_ez
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
35
53
|
end
|
data/lib/ez/schema_modifier.rb
CHANGED
@@ -3,13 +3,14 @@ module EZ
|
|
3
3
|
|
4
4
|
attr_reader :db, :spec
|
5
5
|
|
6
|
-
def initialize(model_spec)
|
6
|
+
def initialize(model_spec, silent = false)
|
7
|
+
@silent = silent
|
7
8
|
@spec = model_spec
|
8
9
|
connect_to_database
|
9
10
|
end
|
10
11
|
|
11
|
-
def self.migrate(model_spec)
|
12
|
-
self.new(model_spec).migrate
|
12
|
+
def self.migrate(model_spec, silent = false)
|
13
|
+
self.new(model_spec, silent).migrate
|
13
14
|
end
|
14
15
|
|
15
16
|
def migrate
|
@@ -21,7 +22,7 @@ module EZ
|
|
21
22
|
if @changed
|
22
23
|
update_schema_version
|
23
24
|
else
|
24
|
-
puts "
|
25
|
+
puts "All tables are up-to-date."
|
25
26
|
end
|
26
27
|
|
27
28
|
return @changed
|
@@ -55,15 +56,15 @@ module EZ
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def display_change(message)
|
58
|
-
puts message
|
59
|
+
puts message unless @silent
|
59
60
|
@changed = true
|
60
61
|
end
|
61
62
|
|
62
63
|
def add_missing_columns(model_name, columns, assume_missing = false)
|
63
64
|
table_name = model_name.tableize
|
64
|
-
|
65
|
-
|
66
|
-
col_type =
|
65
|
+
# {"nickname"=>{:type=>"string", :default=>nil}, "password_digest"=>{:type=>"string", :default=>nil}, "created_at"=>{:type=>"datetime", :default=>nil}, "updated_at"=>{:type=>"datetime", :default=>nil}, "course_id"=>{:type=>"integer", :default=>"(0)"}, "email"=>{:type=>"string", :default=>nil}, "full_name"=>{:type=>"string", :default=>nil}, "admin"=>{:type=>"boolean", :default=>true}}
|
66
|
+
columns.each do |col_name, data|
|
67
|
+
col_type = data[:type]
|
67
68
|
if !assume_missing && db.column_exists?(table_name, col_name.to_sym)
|
68
69
|
unless db.column_exists?(table_name, col_name.to_sym, col_type.to_sym)
|
69
70
|
display_change "Changing column type for '#{col_name}' to #{col_type}"
|
@@ -93,16 +94,6 @@ module EZ
|
|
93
94
|
display_change "Defining new table for model '#{model_name}'."
|
94
95
|
db.create_table table_name
|
95
96
|
add_missing_columns model_name, columns, true
|
96
|
-
# columns.each do |column|
|
97
|
-
# name = column.keys.first
|
98
|
-
# col_type = column[name]
|
99
|
-
# options = {}
|
100
|
-
# options[:default] = false if col_type.to_sym == :boolean
|
101
|
-
# t.send(col_type, name, options)
|
102
|
-
# end
|
103
|
-
# # t.timestamps
|
104
|
-
# end
|
105
|
-
# end
|
106
97
|
filename = "app/models/#{model_name.underscore}.rb"
|
107
98
|
unless Rails.env.production? || File.exists?(filename)
|
108
99
|
display_change "Creating new model file: #{filename}"
|
@@ -121,12 +112,12 @@ module EZ
|
|
121
112
|
def remove_dead_columns
|
122
113
|
tables.each do |table_name|
|
123
114
|
model_name = table_name.classify.to_s
|
115
|
+
|
124
116
|
if @spec.has_key?(model_name)
|
125
|
-
|
126
|
-
spec_columns = @spec[model_name].map
|
127
|
-
|
128
|
-
|
129
|
-
dead_columns = columns - spec_columns
|
117
|
+
db_columns = db.columns(table_name).map { |column| column.name.to_sym } - [:id, :created_at, :updated_at]
|
118
|
+
spec_columns = @spec[model_name].keys.map(&:to_sym)
|
119
|
+
dead_columns = db_columns - spec_columns
|
120
|
+
|
130
121
|
if dead_columns.any?
|
131
122
|
dead_columns.each do |dead_column_name|
|
132
123
|
display_change "Removing unused column '#{dead_column_name}' from model '#{model_name}'"
|
@@ -148,10 +139,26 @@ module EZ
|
|
148
139
|
|
149
140
|
dead_tables.each do |table_name|
|
150
141
|
model_name = table_name.classify
|
142
|
+
display_change "Yo"
|
151
143
|
display_change "Dropping model #{model_name}"
|
152
144
|
db.drop_table(table_name)
|
153
|
-
|
154
|
-
|
145
|
+
begin
|
146
|
+
filename = "app/models/#{model_name.underscore}.rb"
|
147
|
+
code = IO.read(filename)
|
148
|
+
matched = IO.read(filename) =~ /\s*class #{model_name} < ActiveRecord::Base\s+end\s*/
|
149
|
+
|
150
|
+
display_change "-" * 20
|
151
|
+
display_change matched
|
152
|
+
display_change code
|
153
|
+
display_change "-" * 20
|
154
|
+
|
155
|
+
if matched
|
156
|
+
display_change "Deleting file #{filename}"
|
157
|
+
File.unlink(filename)
|
158
|
+
end
|
159
|
+
rescue => e
|
160
|
+
display_change "Could not delete old model #{model_name.underscore}.rb."
|
161
|
+
end
|
155
162
|
end
|
156
163
|
end
|
157
164
|
|
data/lib/ez/version.rb
CHANGED
data/lib/tasks/ez_tasks.rake
CHANGED
@@ -8,16 +8,21 @@ namespace :ez do
|
|
8
8
|
f.puts <<-EOS
|
9
9
|
# Example table for a typical Book model.
|
10
10
|
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
Book
|
12
|
+
title: string
|
13
|
+
price: integer
|
14
|
+
author: string
|
15
|
+
summary: text
|
16
|
+
hardcover: boolean
|
17
17
|
#
|
18
|
-
# Follow the syntax exactly
|
19
|
-
#
|
20
|
-
#
|
18
|
+
# Indent consistently! Follow the above syntax exactly.
|
19
|
+
# Typical column choices are: string, text, integer, boolean, date, and datetime.
|
20
|
+
#
|
21
|
+
# Default column values can be specified like this:
|
22
|
+
# price: integer(0)
|
23
|
+
#
|
24
|
+
# Have fun!
|
25
|
+
|
21
26
|
EOS
|
22
27
|
end
|
23
28
|
end
|
@@ -29,7 +34,8 @@ EOS
|
|
29
34
|
|
30
35
|
|
31
36
|
desc "Attempts to update the database schema and model files with minimal data loss."
|
32
|
-
task :tables => [:environment
|
37
|
+
task :tables => [:environment] do
|
38
|
+
puts "Running ez:tables..."
|
33
39
|
if File.exists?('db/models.yml')
|
34
40
|
if EZ::DomainModeler.update_tables
|
35
41
|
Rake::Task["db:schema:dump"].invoke unless Rails.env.production?
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ez
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Cohen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hirb
|