schofield 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,27 +1,27 @@
1
1
  module Schofield
2
-
2
+
3
3
  module Generators
4
4
 
5
5
  class Level
6
-
6
+
7
7
  COLUMNS_TO_IGNORE = %w( ^created_at$ ^updated_at$ _content_type$ _file_size$ _updated_at$ _type$ ^type$ ^crypted_password$ ^password_salt$ ^persistence_token$ ^perishable_token$ ^login_count$ ^failed_login_count$ ^last_request_at$ ^current_login_at$ ^last_login_at$ ^current_login_ip$ ^last_login_ip$ )
8
-
8
+
9
9
  class << self; attr_reader :columns_to_ignore end
10
-
10
+
11
11
  def self.tables_to_ignore= tables
12
12
  @columns_to_ignore = ( COLUMNS_TO_IGNORE + tables.map{ |m| "^#{m.singularize}_id$" } )
13
13
  end
14
-
15
-
16
- attr_reader :name, :parent_associations, :attributes, :superclass
14
+
15
+
16
+ attr_reader :model, :name, :parent_associations, :attributes, :superclass
17
17
  attr_accessor :child_associations, :subclasses
18
18
 
19
19
  delegate :validations,
20
20
  :validations?,
21
- :attr_protecteds,
22
- :attr_protecteds?,
23
- :acts_as_markdowns,
24
- :acts_as_markdowns?,
21
+ :attr_accessors,
22
+ :attr_accessors?,
23
+ :attr_accessibles,
24
+ :attr_accessibles?,
25
25
  :attachments?,
26
26
  :to_s_string,
27
27
  :attached_files,
@@ -41,135 +41,135 @@ module Schofield
41
41
  add_parent_associations
42
42
  add_attributes
43
43
  end
44
-
45
-
44
+
45
+
46
46
  # Inheritence
47
-
47
+
48
48
  def subclass?
49
49
  @superclass.present?
50
50
  end
51
-
51
+
52
52
  def superclass?
53
53
  @subclasses.any?
54
54
  end
55
-
56
-
55
+
56
+
57
57
  # Join table
58
-
58
+
59
59
  def join?
60
60
  @join ||= @model.columns.select { |c| c.name.match(/_id$/) }.length == 2 && @model.columns.select { |c| !%w( id created_at updated_at position ).include?(c.name) }.length == 2
61
61
  end
62
-
62
+
63
63
  def other_parent_name parent_name
64
64
  @parent_associations.find{ |a| a.parent_name != parent_name }.parent_name
65
65
  end
66
-
67
-
66
+
67
+
68
68
  # Polymorphism
69
-
69
+
70
70
  def polymorphic?
71
71
  @polymorphic ||= polymorphic_name.present?
72
72
  end
73
-
73
+
74
74
  def polymorphic_name
75
75
  match_data = nil
76
76
  @polymorphic_name ||= @model.columns.find { |c| match_data = c.name.match(/^(.+)_type$/) } ? match_data[1] : nil
77
77
  end
78
-
79
-
78
+
79
+
80
80
  # Nesting
81
-
81
+
82
82
  def nested?
83
- @parent_associations.find(&:nest?).present?
83
+ @parent_associations.any?(&:nest?)
84
84
  end
85
-
85
+
86
86
  def nests?
87
- @child_associations.find(&:nest?).present?
87
+ @child_associations.any?(&:nest?)
88
88
  end
89
-
89
+
90
90
  def nested_associations
91
91
  if superclass? then []
92
92
  else
93
93
  associations = @child_associations + ( subclass? ? @superclass.child_associations : [] )
94
94
  end
95
95
  end
96
-
96
+
97
97
  def nested_levels
98
98
  nested_associations.select(&:nest?).map(&:child)
99
99
  end
100
-
101
-
100
+
101
+
102
102
  # Associations and cardinality
103
-
103
+
104
104
  def belongs_to?
105
105
  @parent_associations.any?
106
106
  end
107
-
107
+
108
108
  def belongs_to_one_names
109
109
  @parent_associations.select(&:one_to_one?).map(&:parent_name)
110
110
  end
111
-
111
+
112
112
  def belongs_to_one?
113
- @parent_associations.find(&:one_to_one?).present?
113
+ @parent_associations.any?(&:one_to_one?)
114
114
  end
115
-
115
+
116
116
  def has_ones?
117
- @child_associations.find(&:one_to_one?).present?
117
+ @child_associations.any?(&:one_to_one?)
118
118
  end
119
-
119
+
120
120
  def has_manies?
121
- @child_associations.find(&:one_to_many?).present?
121
+ @child_associations.any?(&:one_to_many?)
122
122
  end
123
-
123
+
124
124
  def has_ones
125
125
  @child_associations.select(&:one_to_one?).map(&:child)
126
126
  end
127
-
127
+
128
128
  def has_manies
129
129
  @child_associations.select(&:one_to_many?).map(&:child)
130
130
  end
131
-
132
-
131
+
132
+
133
133
  # Combos
134
-
134
+
135
135
  def routes?
136
136
  !nested? && !superclass? && !belongs_to_one? && !join?
137
137
  end
138
-
138
+
139
139
  def controllers?
140
140
  !superclass? && name != 'user' && !belongs_to_one?
141
141
  end
142
-
142
+
143
143
  def views?
144
144
  controllers? && !join?
145
145
  end
146
-
146
+
147
147
  def models?
148
148
  name != 'user'
149
149
  end
150
-
150
+
151
151
  def tables?
152
152
  !belongs_to_one? && !superclass?
153
153
  end
154
-
155
-
156
-
154
+
155
+
156
+
157
157
  # Sortable
158
-
158
+
159
159
  def sortable?
160
160
  @sortable
161
161
  end
162
-
163
-
162
+
163
+
164
164
  # Form
165
-
165
+
166
166
  def multipart?
167
- attachments? || has_ones.find(&:attachments?).present?
167
+ attachments? || has_ones.any?(&:attachments?)
168
168
  end
169
-
170
-
169
+
170
+
171
171
  # Association ancestry
172
-
172
+
173
173
  def ancestry
174
174
  level = self
175
175
  nested_ins = []
@@ -189,99 +189,99 @@ module Schofield
189
189
  nested_ins.reverse
190
190
  end
191
191
 
192
-
192
+
193
193
  # Form fields
194
-
194
+
195
195
  def attribute_of_nesting_parent? attribute
196
196
  attribute.model_name && parent_associations.select(&:nest?).map(&:parent_name).include?(attribute.model_name)
197
197
  end
198
-
198
+
199
199
  def polymorphic_attribute? attribute
200
200
  polymorphic_name && attribute.model_name == polymorphic_name
201
201
  end
202
-
202
+
203
203
  def form_field? attribute
204
- attribute.name != 'position' && !polymorphic_attribute?(attribute) && !attribute_of_nesting_parent?(attribute)
204
+ !%w( position slug ).include?(attribute.name) && attribute.name !~ /_fingerprint$/ && !polymorphic_attribute?(attribute) && !attribute_of_nesting_parent?(attribute)
205
205
  end
206
-
207
-
208
-
206
+
207
+
208
+
209
209
  private
210
-
210
+
211
211
  def add_attributes
212
212
  @attributes = Attributes.new
213
213
  @model.columns.each do |column|
214
214
  add_attribute(column) unless ignore?(column) || (polymorphic? && column.name =~ /^#{polymorphic_name}_id$/)
215
215
  end
216
216
  end
217
-
217
+
218
218
  def add_attribute column
219
219
  attribute = @attributes.new_attribute(column, belongs_to_one_names.include?(column.name.gsub(/_id$/, '')))
220
220
  set_sortable if attribute.name == 'position'
221
221
  end
222
-
222
+
223
223
  def set_sortable
224
224
  unless superclass?
225
225
  @sortable = true
226
226
  Levels.sortable = @name
227
227
  end
228
228
  end
229
-
229
+
230
230
  # Nesting refers to nested routes, embedding refers to nested_attributes_for
231
231
  # Assuming that a polymorphic model has no parents other than it's polymorphically associated parents
232
232
  # If model has a one-to-one relationship with a parent, no nesting will occur as child will be embedded in parent
233
233
  # Only allowing child to be nested under one parent or if polymorphic, the polymorphically associated parents
234
234
  def add_parent_associations
235
-
235
+
236
236
  if polymorphic?
237
-
237
+
238
238
  answer = Responses.get("Which models are #{polymorphic_name}?")
239
239
  answer.split(/[^\w]+/).map(&:underscore).each do |parent_name|
240
240
  @parent_associations << Association.new(self, parent_name, one_to_one?(polymorphic_name), polymorphic_name)
241
241
  end
242
-
242
+
243
243
  else
244
-
244
+
245
245
  any_one_to_ones = false
246
246
  @model.columns.each do |column|
247
- if (match_data = column.name.match(/^(.+)_id$/)).present?
247
+ if (match_data = column.name.match(/^(.+)_id$/)).present? && Levels.exists?(match_data[1])
248
248
  parent_name = match_data[1]
249
249
  is_one_to_one = one_to_one?(parent_name)
250
250
  any_one_to_ones = true if is_one_to_one
251
251
  @parent_associations << Association.new(self, parent_name, is_one_to_one)
252
252
  end
253
253
  end
254
-
254
+
255
255
  if @parent_associations.any? && !any_one_to_ones
256
256
  @parent_associations.length == 1 ? ask_if_nested : ask_where_to_nest
257
257
  end
258
258
  end
259
259
  end
260
-
260
+
261
261
  def one_to_one? parent_name
262
262
  @one_to_one ||= %w( y yes ).include?(Responses.get("#{parent_name.gsub('_', ' ')} HAS ONE #{@human_name}? [N]").downcase)
263
263
  end
264
-
264
+
265
265
  def ask_if_nested
266
266
  question = "Do you wish to nest #{@human_name} in #{@parent_associations.first.parent_name}? [yes]"
267
267
  @parent_associations.first.nest = true unless %w( n no ).include?(Responses.get(question).downcase.strip)
268
- end
269
-
268
+ end
269
+
270
270
  def ask_where_to_nest
271
271
  question = "Where do you wish to nest #{@human_name}? nowhere(n), "
272
272
  question += @parent_associations.enum_with_index.map{ |n,i| "#{n.parent_name.gsub('_', ' ')}(#{i})" }.join(', ') + ' [n]'
273
273
  answer = Responses.get(question)
274
274
  @parent_associations[answer.to_i].nest = true unless answer == 'n' || answer.blank?
275
275
  end
276
-
276
+
277
277
  def ignore? column
278
278
  self.class.columns_to_ignore.each do |string|
279
279
  return true if column.name.match(/#{string}/)
280
280
  end
281
281
  column.primary
282
282
  end
283
-
283
+
284
284
  end
285
-
285
+
286
286
  end
287
287
  end
@@ -1,18 +1,19 @@
1
1
  module Schofield
2
-
2
+
3
3
  module Generators
4
4
 
5
5
  class Levels
6
-
6
+
7
7
  class << self; attr_reader :all, :hierarchy, :sortables end
8
-
8
+
9
9
  @all = []
10
10
  @names = {}
11
11
  @sortables = {}
12
-
13
-
14
-
12
+
13
+
14
+
15
15
  def self.models= models
16
+ @model_names = models.map{ |m| m.name.underscore }
16
17
  models.each do |model|
17
18
  if polymorphic_model?(model)
18
19
  superclass = add_level(model)
@@ -25,28 +26,32 @@ module Schofield
25
26
  end
26
27
  end
27
28
  end
28
-
29
+
29
30
  def self.sortables
30
31
  @sortables.keys
31
32
  end
32
-
33
+
33
34
  def self.sortable=sortable
34
35
  @sortables[sortable] = true
35
36
  end
36
-
37
+
37
38
  def self.find name
38
39
  @all[@names[name]]
39
40
  end
40
41
 
41
-
42
-
42
+ def self.exists? name
43
+ @model_names.include?(name.to_s)
44
+ end
45
+
46
+
47
+
43
48
  private
44
-
45
-
49
+
50
+
46
51
  def self.polymorphic_model? model
47
52
  model.columns.find { |c| c.name == 'type' }.present?
48
53
  end
49
-
54
+
50
55
  def self.subclasses model
51
56
  begin
52
57
  answer = Responses.get "Which models extend #{model.name}?"
@@ -61,14 +66,14 @@ module Schofield
61
66
  end
62
67
  subclasses
63
68
  end
64
-
69
+
65
70
  def self.add_level model, superclass=nil
66
71
  level = Level.new(model, superclass)
67
72
  @all << level
68
73
  @names[model.name.underscore] = @all.length - 1
69
74
  level
70
75
  end
71
-
76
+
72
77
  end
73
78
  end
74
79
  end
@@ -0,0 +1,17 @@
1
+ module Schofield
2
+
3
+ module Generators
4
+
5
+ class Navigation
6
+
7
+ def self.generate
8
+ Levels.all.select(&:routes?).inject("\n %ul\n %li.toplevel") do |memo, level|
9
+ memo += "\n\n - if permitted_to?(:read, :#{level.name.pluralize})"
10
+ memo += "\n %li{ :class => nav_classes('#{level.model.name}') }= link_to '#{level.model.name.titleize.pluralize}', admin_#{level.name.pluralize}_path"
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -1,14 +1,14 @@
1
1
  module Schofield
2
-
2
+
3
3
  module Generators
4
-
4
+
5
5
  class Responses
6
-
6
+
7
7
  class << self; attr_accessor :generator, :re_ask end
8
-
8
+
9
9
  @file = File.join(Rails.root, 'tmp', 'answers.txt')
10
-
11
-
10
+
11
+
12
12
  def self.get question
13
13
  @question = question
14
14
  if re_ask || (answer = past_answer).nil?
@@ -16,31 +16,31 @@ module Schofield
16
16
  end
17
17
  answer || ''
18
18
  end
19
-
19
+
20
20
  def self.ask
21
21
  re_ask = true
22
22
  answer = generator.ask(@question)
23
23
  @answers ||= {}
24
24
  @answers[@question] = answer || ''
25
25
  end
26
-
26
+
27
27
  def self.past_answer
28
28
  self.past_answers[@question]
29
29
  end
30
-
30
+
31
31
  def self.past_answers
32
32
  @answers ||= File.exists?(@file) ? File.open(@file, 'rb') { |f| Marshal.load(f) } : {}
33
33
  end
34
-
34
+
35
35
  def self.save
36
36
  File.open(@file, 'wb') { |io| Marshal.dump(@answers, io) }
37
37
  end
38
-
38
+
39
39
  def self.say string
40
40
  generator.say(string)
41
41
  end
42
-
42
+
43
43
  end
44
-
44
+
45
45
  end
46
46
  end