dmapper 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+ 0.2 July 4th, 2011
2
+
3
+ * Properties now maintain correct order
4
+ * Added tiny 'helpers' (e.g. Time.now becomes proc => { Time.now })
5
+ * Switched the order of operations (from type:field:options to field:type:options)
6
+ * Lazy accepts true/false/fields
7
+ * Added a verbose option -v
8
+ * Added a testing option -t
9
+ * Added a backup option -b
10
+ * Added a silent/suppress option -s
11
+ * Much better validation handlers (still needs quite a bit of work)
12
+ * Added association support!
13
+
14
+ 0.1 - July 3rd, 2011
15
+
16
+ * Initial Release
@@ -1,6 +1,8 @@
1
1
  = DMap
2
2
 
3
- DMap is a generator for creating models with {DataMapper}[http://datamapper.org]. It's currently under a lot of development but I, as well as others, use it when for production use. As of right now majority of the validations work as expected and property types.
3
+ DMap is a generator for creating models with {DataMapper}[http://datamapper.org]. It's currently under a lot of development but I, as well as others, use it for production use. DataMapper gems are not even required for this gem/tool.
4
+
5
+ "DMap a shorter way for saying, and using, DataMapper"
4
6
 
5
7
  == Installation
6
8
  gem install dmapper
@@ -9,53 +11,60 @@ DMap is a generator for creating models with {DataMapper}[http://datamapper.org]
9
11
 
10
12
  As of right now the only command available is <tt>new</tt>. Here's a basic example of DMap to explain the structure...
11
13
 
12
- dmap new user id str:name str:email:required,unique str:password:required
14
+ dmap new user id name:string email:str:required,unique str:password:required
13
15
 
14
16
  The first, after <tt>dmap new</tt>, is the [table]. You can create multiple tables at a time by adding a comma (,). Every argument (<tt>space</tt>) is a separate [field]. Fields are divided into three sections by a colon (<tt>:</tt>). The first part is the field's [type]. The second part is the field's name, and the last part marks additional options for that field (explained later).
15
17
 
18
+ == Options
19
+
20
+ <b><tt>-b, --backup</tt></b>:: Backs up the current model files (renames them to *.rb.bk)
21
+ <b><tt>-h, --help</tt></b>:: Displays help message
22
+ <b><tt>-s, --silent</tt></b>:: If you entered incorrect values for a validation just suppress it and continue on.
23
+ <b><tt>-t, --test</tt></b>:: Displays what DMap would have made into a file onto the screen.
24
+ <b><tt>-v, --verbose</tt></b>:: Will print out the model(s) after changes have been made
25
+
16
26
  == Examples
17
27
 
18
28
  Using DMap is incredibly easy once you learn the basic structure of it all. Here's a quick example...
19
29
 
20
- dmap new user id str:username str:email text:signature
30
+ dmap new user id username:str email:str signature:text
21
31
 
22
32
  Which creates (user.rb file in the folder that you're currently in)...
23
33
 
24
34
  class User
25
35
  include DataMapper::Resource
26
36
 
27
- property :signature
28
- property :username
29
- property :id
30
- property :email
37
+ property :id, Serial
38
+ property :username, String
39
+ property :email, String
40
+ property :signature, Text
31
41
 
32
42
 
33
43
  end
34
44
 
35
45
  Let's get a little more "complex"
36
46
 
37
- dmap new user id str:username str:email,required str:name:required,unique str:password datetime:date_created:default=Time.now text:signature
47
+ dmap new user id username:str email:str:required name:str:required,unique password:str date_crtd:datetime:default=DateTime.now signature:text
38
48
 
39
49
  Which produces...
40
50
 
41
51
  class User
42
52
  include DataMapper::Resource
43
53
 
44
- property :name, String, :required => true, :unique => true
45
- property :required, String
46
- property :signature, Text
47
- property :username, String
48
54
  property :id, Serial
55
+ property :username, String
56
+ property :email, String, :required => true
57
+ property :name, String, :required => true, :unique => true
49
58
  property :password, String
50
- property :date_created, DateTime, :default => Time.now
51
- property :email, String
59
+ property :date_crtd, DateTime, :default => proc => { DateTime.now }
60
+ property :signature, Text
52
61
 
53
62
 
54
63
  end
55
64
 
56
65
  I know, still not that impressive, let's try something a tad more difficult...
57
66
 
58
- dmap new user,user_copy id str:first_name,last_name datetime:name1:default=true,length=1..5,presence_of=title-publish20..50,length_of=1,absent,confirm=field,format=email_address,primitive,unique,accessor=private str:Name1
67
+ dmap new user,user_copy id first_name,last_name:str name1:datetime:default=true,length=1..5,presence_of=title-publish20..50,length_of=1,absent,confirm=field,format=email_address,primitive,unique,accessor=private Name1:str
59
68
 
60
69
  Which creates (along with a copy model "UserCopy" of the same exact thing)
61
70
 
@@ -63,10 +72,10 @@ Which creates (along with a copy model "UserCopy" of the same exact thing)
63
72
  include DataMapper::Resource
64
73
 
65
74
  property :id, Serial
66
- property :name1, DateTime, :default => true, :accessor => private, :unique => true, :length => 1..5
75
+ property :first_name, String
67
76
  property :last_name, String
77
+ property :name1, DateTime, :default => true, :length => 1..5, :unique => true, :accessor => :private
68
78
  property :Name1, String
69
- property :first_name, String
70
79
 
71
80
  validates_format_of :name1, :as => :email_address
72
81
  validates_confirmation :name1, :confirm => :field
@@ -81,21 +90,19 @@ Which creates (along with a copy model "UserCopy" of the same exact thing)
81
90
 
82
91
  Here is a list of all the types available from DataMapper, which ones we support, and custom aliases.
83
92
 
84
- <table>
85
- [DataMapper Property Type]</td><td>[DMap Command]</td><td>[Aliases]
86
- <tt>Boolean</tt>::<tt>Boolean</tt>::<tt>Bool</tt>
87
- <tt>String</tt>::<tt>String</tt>::<tt>Str, S</tt>
88
- <tt>Text</tt>::<tt>Text</tt>::<tt>Txt</tt>
89
- <tt>Float</tt>::<tt>Float</tt>::<tt>F</tt>
90
- <tt>Integer</tt>::<tt>Integer</tt>::<tt>Int, I</tt>
91
- <tt>Decimal</tt>::<tt>Decimal</tt>::<tt>Dec</tt>
92
- <tt>DateTime</tt>::<tt>DateTime</tt>::<tt>DT</tt>
93
- <tt>Date</tt>::<tt>Date</tt>::<tt>D</tt>
94
- <tt>Time</tt>::<tt>Time</tt>::<tt>T</tt>
95
- <tt>Object</tt>::<tt>Object</tt>::<tt>Obj</tt>
96
- <tt>Discriminator</tt>::<tt>Discriminator</tt>::<tt>Disc</tt>
97
- <tt>Binary</tt>::<tt>Binary</tt>::<tt>Blob, B</tt>
98
- </table>
93
+ <b>DataMapper Property Type</b>:: <b>DMap Command/Aliases</b>
94
+ <tt>Boolean</tt>:: <tt>boolean</tt>, <tt>bool</tt>
95
+ <tt>String</tt>:: <tt>string</tt>, <tt>str, s</tt>
96
+ <tt>Text</tt>:: <tt>text</tt>, <tt>txt</tt>
97
+ <tt>Float</tt>:: <tt>float</tt>, <tt>f</tt>
98
+ <tt>Integer</tt>:: <tt>integer</tt>, <tt>int, i</tt>
99
+ <tt>Decimal</tt>:: <tt>decimal</tt>, <tt>dec</tt>
100
+ <tt>DateTime</tt>:: <tt>datetime</tt>, <tt>dt</tt>
101
+ <tt>Date</tt>:: <tt>date</tt>, <tt>d</tt>
102
+ <tt>Time</tt>:: <tt>time</tt>, <tt>t</tt>
103
+ <tt>Object</tt>:: <tt>object</tt>, <tt>obj</tt>
104
+ <tt>Discriminator</tt>:: <tt>discriminator</tt>, <tt>disc</tt>
105
+ <tt>Binary</tt>:: <tt>binary</tt>, <tt>blob, b</tt>
99
106
 
100
107
  More coming soon!
101
108
 
@@ -103,7 +110,7 @@ More coming soon!
103
110
 
104
111
  This part belongs in the third section of the command for example:
105
112
 
106
- dmap new user id str:name:[required,accessor=private]
113
+ dmap new user id name:str:<b>required,accessor=private</b>
107
114
 
108
115
  Each validator is separated by a comma (<tt>,</tt>) and can have a value placed within it by an equal sign (<tt>=</tt>). The property name will look like...
109
116
 
@@ -112,11 +119,11 @@ Each validator is separated by a comma (<tt>,</tt>) and can have a value placed
112
119
 
113
120
  === Property Validator List
114
121
 
115
- [DataMapper's List]:: [DMap Command]
122
+ <b>DataMapper's List</b>:: <b>DMap Command</b>
116
123
  <tt>required</tt>:: <tt>required</tt>
117
124
  <tt>default</tt>:: <tt>default</tt>
118
125
  <tt>key</tt>:: <tt>key</tt>
119
- <tt>lazy</tt>:: <tt>lazy</tt> - Only accepts "false" for now
126
+ <tt>lazy</tt>:: <tt>lazy</tt>
120
127
  <tt>accessor</tt>:: <tt>accessor</tt>
121
128
  <tt>writer</tt>:: <tt>writer</tt>
122
129
  <tt>reader</tt>:: <tt>reader</tt>
@@ -127,27 +134,39 @@ That's all the ones I know for now, let me know if there are more!
127
134
 
128
135
  A list of all of the validates_*_of commands and which DMap currently supports
129
136
 
130
- [DataMapper's List]:: [DMap Command] [Notes]
131
- <tt>validates_absence_of</tt>:: <tt>absence, absent</tt>
132
- <tt>validates_acceptance_of</tt>:: <tt>acceptance, accept</tt>:: Does not accept :allow_nil options yet
133
- <tt>validates_with_block</tt>:: </td><td>Unsupported at this time
137
+ Note: DMap currently does not support :allow_nil parameters. This will change in the future.
138
+
139
+ <b>DataMapper's List</b>:: <b>DMap Command</b>
140
+ <tt>validates_absence_of</tt>:: <tt>absence, absent</tt>
141
+ <tt>validates_acceptance_of</tt>:: <tt>acceptance, accept</tt>
142
+ <tt>validates_with_block</tt>:: Unsupported at this time
134
143
  <tt>validates_confirmation_of</tt>:: <tt>confirmation, confirm</tt>
135
144
  <tt>validates_format_of</tt>:: <tt>format</tt>
136
145
  <tt>validates_length_of</tt>:: <tt>length_of</tt>
137
146
  <tt>validates_with_method</tt>:: <tt>withmethod, method</tt>
138
- <tt>validates_numericality_of</tt>:: <tt>Unsupported</tt>
147
+ <tt>validates_numericality_of</tt>:: Unsupported
139
148
  <tt>validates_primitive_type_of</tt>:: <tt>primitive</tt>
140
149
  <tt>validates_presence_of</tt>:: <tt>presence, present</tt>
141
150
  <tt>validates_uniqueness_of</tt>:: <tt>uniqueness</tt>
142
151
  <tt>validates_within</tt>:: <tt>within</tt>
143
152
 
153
+ == Associations
154
+
155
+ <b>DataMapper Command</b>:: <b>DMap Command</b>
156
+ <tt>has 1</tt>:: <tt>has1, hasone</tt>
157
+ <tt>has n</tt>:: <tt>hasn</tt>
158
+ <tt>belongs_to</tt>:: <tt>belongs_to, belongs</tt>
159
+ <tt>has_and_belongs_to_many</tt>:: <tt>hasmany</tt>
160
+
161
+ Note: use hasn when wanting to use :through => :model and hasmany for wanting to :through => Resource
162
+
163
+ Also, conditions are <b>not</b> supported through this generator (suggestions on this could be implemented would be helpful).
164
+
144
165
  == To Do
145
166
 
146
- * Add a verbose option
147
167
  * Add a way to add/edit/remove columns from pre-existing tables
148
- * Backup option before overwriting
149
168
  * All of the misc. property types
150
- * Better validation checkers
151
- * Associations! (this will be done first)
152
169
  * Template system similar to {Sinatra::Fedora's}[https://github.com/durango/sinatra_fedora] hatrack option
153
- * Better documentation!
170
+ * Better documentation!
171
+ * Migrations! (This will most likely be started after DM core team has finished the Veritas system).
172
+ * Conditions with associations?
data/bin/dmap CHANGED
@@ -14,6 +14,28 @@ opt_parser = OptionParser.new do |opt|
14
14
  opt.separator " new <model name> [options]: Creates a new model"
15
15
  opt.separator " e.g. dmap new User serial:id str:name:length=1..5,unique str:email text:signature"
16
16
  opt.separator ""
17
+
18
+ opt.on('-h', '--help', 'Displays this screen') do
19
+ puts opt
20
+ exit 1
21
+ end
22
+
23
+ opt.on('-v', '--verbose', 'Will print out the model(s) after changes have been made') do
24
+ DMap::Commands.options['verbose'] = true
25
+ end
26
+
27
+ opt.on('-b', '--backup', 'Backs up the old model from "model.rb" into "model.rb.bk"') do
28
+ DMap::Commands.options['backup'] = true
29
+ end
30
+
31
+ opt.on('-t', '--test', 'Displays what DMap would have made into a file onto the screen.') do
32
+ DMap::Commands.options['test'] = true
33
+ DMap::Commands.options['verbose'] = true
34
+ end
35
+
36
+ opt.on('-s', '--silent', 'If you entered incorrect values for a validation just suppress it and continue on.') do
37
+ DMap::Commands.options['silent'] = true
38
+ end
17
39
  end
18
40
 
19
41
  opt_parser.parse!
@@ -23,14 +45,14 @@ if ARGV[0].nil?
23
45
  exit 1
24
46
  end
25
47
 
26
- unless DMap::Commands.exists?(ARGV[0])
48
+ unless DMap::Commands.exists? ARGV[0]
27
49
  puts ARGV[0] + " is not a valid command."
28
50
  puts opt_parser
29
51
  exit 1
30
52
  end
31
53
 
32
54
  # safe guard table names
33
- table_names = ARGV[1].match /^\[*([a-zA-Z0-9,_]+)\]*$/
55
+ table_names = ARGV[1].to_s.match /^\[*([a-zA-Z0-9,_]+)\]*$/
34
56
  if table_names.nil?
35
57
  puts "Invalid table name, only characters A-Z, 0-9, and _ are allowed."
36
58
  puts opt_parser
@@ -45,7 +67,8 @@ table_names[1].split(',').each do |table|
45
67
  table.downcase!
46
68
 
47
69
  DMap::Tables.add model_name, model_name.underscore
48
- if File.file? "./#{table}.rb"
70
+ File.rename("./#{table}.rb", "./#{table}.rb.bk") if File.file? "./#{table}.rb" and DMap::Commands.options['backup'] == true
71
+ if File.file? "./#{table}.rb" and DMap::Commands.options['test'] != true
49
72
  puts "A model with the name of #{table} already exists."
50
73
  exit 1
51
74
  end
@@ -53,40 +76,42 @@ end
53
76
 
54
77
  ARGV[2..-1].each do |command|
55
78
  # TODO: Add a shortcut module/class
56
- command = "serial:id" if command == "id"
79
+ command = "id:serial" if command == "id"
57
80
 
58
81
  keys = command.split(':')
59
- unless DMap::Fields.list.include?(keys[0]) or DMap::Properties.valid?(keys[0].camelcase)
60
- puts keys[0] + " is not a valid property or field"
82
+ keys[1] = '' if keys[1].class.name == "NilClass"
83
+
84
+ unless DMap::Fields.list.include? keys[1] or DMap::Properties.valid? keys[1].camelcase
85
+ puts keys[1] + " is not a valid property or field"
61
86
  puts opt_parser
62
87
  exit 1
63
88
  end
64
89
 
65
90
  # Check if the "command" is a key first (keys always overrule)
66
- if DMap::Fields.list.include?(keys[0])
67
- keys.unshift(DMap::Fields.list[keys[0]])
91
+ if DMap::Fields.list.include?(keys[1])
92
+ keys.unshift(DMap::Fields.list[keys[1]])
68
93
  else
69
94
  # Can't create two fields with the same name
70
- if DMap::Fields.list.include?(keys[1])
71
- puts keys[1] + " is already a declared field. You cannot declare a field twice."
95
+ if DMap::Fields.list.include?(keys[0])
96
+ puts keys[0] + " is already a declared field. You cannot declare a field twice."
72
97
  puts opt_parser
73
98
  exit 1
74
99
  end
75
100
 
76
101
  # We really only need to do this when we're declaring a field with a type
77
102
  # Gets proper property name (e.g. "Dt" becomes "DateTime")
78
- property_class = DMap::Properties.const_get(keys[0].camelcase)
103
+ property_class = DMap::Properties.const_get(keys[1].camelcase)
79
104
  begin
80
- keys[0] = property_class.superclass.parent_name
105
+ keys[1] = property_class.superclass.parent_name
81
106
  rescue
82
- keys[0] = keys[0].camelcase
107
+ keys[1] = keys[1].camelcase
83
108
  end
84
109
 
85
110
  # Allow to declare multiple fields at once
86
- keys[1].split(',').each do |key|
87
- DMap::Fields.add key, keys[0]
88
- DMap::Tables.list.each do |table|
89
- DMap::Properties.add table, key, keys[0], 'type'
111
+ keys[0].split(',').each do |key|
112
+ DMap::Fields.add key, keys[1]
113
+ DMap::Tables.list.each_value do |table|
114
+ DMap::Properties.add table, key, keys[1], 'type'
90
115
  end
91
116
  end
92
117
  end
@@ -96,52 +121,64 @@ ARGV[2..-1].each do |command|
96
121
  keys[2].split(',').each do |cmds|
97
122
  validation = cmds.split('=')
98
123
 
99
- # Let's check if it's a validates_*_of first
124
+ # Does the validation exist?
125
+ # Check if the validation belongs to the property or within it's own command
100
126
  begin
101
- if DMap::Validations.const_defined? validation[0].camelcase
102
- # See if we're just an alias command...
103
- original_class = DMap::Validations.const_get(validation[0].camelcase)
104
- begin
105
- original_name = original_class.superclass.parent_name
106
- rescue
107
- original_name = validation[0].camelcase
108
- end
109
- original_name = original_name.underscore.downcase
110
-
111
- # Compile all of the otptions for the validation
112
- struct = DMap::Validations.const_get(original_name.camelcase).validate validation[1]
113
-
114
- # Finally, add the validations!
115
- struct.each do |key, value|
116
- DMap::Validations.add keys[1], original_name, key, value unless value.nil? || key == :cmd
117
- end
118
- next
119
- end
120
- end
121
-
122
- # Does the validation exist
123
- property = DMap::Properties.const_get keys[0].capitalize
124
- unless property.respond_to? validation[0] or DMap::Validations.respond_to? validation[0]
125
- puts "Invalid validation command " + validation[0] + " in type " + property.to_s
127
+ validate = DMap::Validations.const_get validation[0].camelcase
128
+ rescue
129
+ validate = DMap::Associations.const_get validation[0].camelcase
130
+ rescue
131
+ puts "Invalid validation command " + validation[0].camelcase + " in type " + validate.class.name.to_s
126
132
  puts opt_parser
127
133
  exit 1
128
134
  end
129
135
 
130
- # Use class specific validation or generic if one doesn't exist
131
- use_method = property.method validation[0] if property.respond_to? validation[0]
132
- use_method = DMap::Validations.method validation[0] unless use_method
136
+ # Do we need a default value?
137
+ begin
138
+ validation[1] ||= validate.default
139
+ rescue
140
+ end
133
141
 
134
- # Check to see if the validation returns true based on our input
135
- unless use_method.call(validation[1]) == true
136
- puts "Invalid value for validation " + validation[0] + " in type " + property.to_s
137
- puts opt_parser
138
- exit 1
142
+ # Store in variable for -s / silent option
143
+ valid_command = validate.method("is_valid?").call validation[1]
144
+ unless valid_command != true
145
+ if !validate.respond_to? "property"
146
+ # Compile all of the options for the validation
147
+ struct = validate.method("validate").call validation[1]
148
+
149
+ # Get the original name
150
+ begin
151
+ original_name = validate.superclass.parent_name.underscore
152
+ rescue
153
+ original_name = validation[0].underscore
154
+ end
155
+
156
+ # Finally, add the validations!
157
+ if struct.is_a?(Hash) or struct.is_a? Hash
158
+ struct.each do |key, value|
159
+ if validate.respond_to? "associations"
160
+ DMap::Associations.add keys[0], original_name, key, value unless value.nil? || key == :cmd
161
+ else
162
+ DMap::Validations.add keys[0], original_name, key, value unless value.nil? || key == :cmd
163
+ end
164
+ end
165
+ end
166
+ else
167
+ # Add the "core" validations (on properties)
168
+ struct = validate.method("validate").call validation[1]
169
+ DMap::Tables.list.each do |k, table|
170
+ validation[1] = true if validation[1].nil?
171
+ DMap::Properties.add table, keys[0], struct, validation[0]
172
+ end
173
+ end
139
174
  end
140
175
 
141
- # Add the "core" validations (on properties)
142
- DMap::Tables.list.each do |table|
143
- validation[1] = true if validation[1].nil?
144
- DMap::Properties.add table, keys[1], validation[1], validation[0]
176
+ if valid_command == false
177
+ puts validation[0] + " validation has an incorrect value for " + keys[0] + "."
178
+ if DMap::Commands.options['silent'] != true
179
+ puts opt_parser
180
+ exit 1
181
+ end
145
182
  end
146
183
  end
147
184
  end
@@ -152,21 +189,6 @@ end
152
189
  #p DMap::Tables.list
153
190
  #p DMap::Properties.list
154
191
  #p DMap::Validations.list
155
- #p DMap::Associations.list TODO
156
-
157
- case ARGV[0]
158
- when "new"
159
- DMap::Tables.list.each do |table|
160
- properties = DMap::Properties.list[table]
161
- validations = DMap::Validations.list
162
- p "Compiling model " + table[0]
163
- obj = $new_block.result(binding)
164
-
165
- handler = File.new(table[1] + ".rb", "w")
166
- handler.write(obj)
167
- handler.close
168
- p table[0] + " saved successfully"
169
- end
170
- else
171
- puts opt_parser
172
- end
192
+ #p DMap::Associations.list
193
+
194
+ DMap::Commands.method("cmd_" + ARGV[0]).call