crud 0.0.3

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1 -0
  3. data/LICENSE.md +674 -0
  4. data/README.md +136 -0
  5. data/Rakefile +72 -0
  6. data/app/assets/images/crud/search-icon.png +0 -0
  7. data/app/assets/javascripts/crud/application.js +17 -0
  8. data/app/assets/javascripts/crud/dashboard.js +7 -0
  9. data/app/assets/javascripts/crud/pagination.js +41 -0
  10. data/app/assets/stylesheets/crud/application.css +27 -0
  11. data/app/assets/stylesheets/crud/dashboard.css +4 -0
  12. data/app/assets/stylesheets/crud/flash_notices.css +19 -0
  13. data/app/assets/stylesheets/crud/pagination.css +104 -0
  14. data/app/assets/stylesheets/dataTables/jquery.dataTables-override.css +20 -0
  15. data/app/controllers/crud/crud_base_controller.rb +28 -0
  16. data/app/controllers/crud/crud_controller.rb +149 -0
  17. data/app/controllers/crud/dashboard_controller.rb +17 -0
  18. data/app/helpers/crud/crud_helper.rb +104 -0
  19. data/app/helpers/crud/dashboard_helper.rb +4 -0
  20. data/app/models/crud/klass_info.rb +166 -0
  21. data/app/models/crud/klass_list.rb +51 -0
  22. data/app/models/crud/menus/development_menu.rb +63 -0
  23. data/app/views/crud/crud/_attribute_value.html.erb +5 -0
  24. data/app/views/crud/crud/_error_messages.html.erb +10 -0
  25. data/app/views/crud/crud/_flash_messages.html.erb +10 -0
  26. data/app/views/crud/crud/_form.html.erb +22 -0
  27. data/app/views/crud/crud/_klass_data.html.erb +117 -0
  28. data/app/views/crud/crud/edit.html.erb +17 -0
  29. data/app/views/crud/crud/index.html.erb +6 -0
  30. data/app/views/crud/crud/index.js.erb +1 -0
  31. data/app/views/crud/crud/new.html.erb +13 -0
  32. data/app/views/crud/crud/show.html.erb +69 -0
  33. data/app/views/crud/dashboard/index.html.erb +15 -0
  34. data/app/views/layouts/crud/application.html.erb +13 -0
  35. data/config/cucumber.yml +8 -0
  36. data/config/initializers/inflections.rb +5 -0
  37. data/config/initializers/rails_engine.rb +8 -0
  38. data/config/initializers/will_paginate.rb +1 -0
  39. data/config/locales/de.yml +3 -0
  40. data/config/locales/en.yml +3 -0
  41. data/config/locales/es.yml +3 -0
  42. data/config/locales/fr.yml +3 -0
  43. data/config/routes.rb +16 -0
  44. data/crud.gemspec +29 -0
  45. data/lib/crud.rb +144 -0
  46. data/lib/crud/engine.rb +23 -0
  47. data/lib/crud/version.rb +3 -0
  48. data/lib/tasks/crud_tasks.rake +4 -0
  49. metadata +157 -0
@@ -0,0 +1,51 @@
1
+ # Processor to create a list of models
2
+ module Crud
3
+ class KlassList
4
+ def initialize
5
+ update
6
+ end
7
+
8
+ def update
9
+ #return if $all_klasses
10
+ all_model_names = []
11
+ ::Crud.model_path.each do |path_element|
12
+ model_files = Dir[ File.join(path_element, '**', '*.rb').to_s ]
13
+ model_names = model_files.map { |item| item.sub(path_element,'').sub(/^\//,'').sub(/\.rb$/,'').camelize.gsub(File::SEPARATOR,'::') }
14
+ all_model_names += model_names
15
+ end
16
+
17
+ klasses = create_klasses_from_model_names(all_model_names)
18
+ #Rails.logger.debug "create_klasses_from_model_names()"
19
+ #klasses.each {|klass| Rails.logger.debug "#{klass}"}
20
+
21
+ $all_klasses = remove_klasses_without_table(klasses).sort_by {|r| r.name.underscore}
22
+ Rails.logger.debug "$all_klasses"
23
+ $all_klasses.each {|klass| Rails.logger.debug "#{klass} (#{klass.name.underscore})"}
24
+ end
25
+
26
+ def all
27
+ $all_klasses
28
+ end
29
+
30
+ private
31
+
32
+ def create_klasses_from_model_names(model_names)
33
+ model_names.inject([]) do |output, model_name|
34
+ klass_name = model_name
35
+ begin
36
+ klass = klass_name.constantize
37
+ output << "::#{klass}".constantize if klass_name == klass.to_s
38
+ rescue Exception => e
39
+ Rails.logger.debug e.message
40
+ end
41
+ output
42
+ end
43
+ end
44
+
45
+ def remove_klasses_without_table(klasses)
46
+ klasses.select { |klass| klass.ancestors.include?(ActiveRecord::Base) && klass.connection.table_exists?(klass.table_name) }
47
+ end
48
+ end
49
+ end
50
+
51
+ # p.to_s if p.respond_to?(:to_s) && /^<.+>$/.match(p.to_s).nil?
@@ -0,0 +1,63 @@
1
+ # Development Menu
2
+ module Crud
3
+ class Menus::DevelopmentMenu < Hash
4
+ def initialize
5
+ root_dir = Crud::Engine.root
6
+
7
+ Dir.glob( File.join(root_dir, 'app', 'controllers', '**', '*_controller.rb') ).sort.each do |controller_file|
8
+ controller_prefix = File.dirname( controller_file.gsub(/^.*controllers/, "").gsub(/^[\\\/]/, "") )
9
+ controller_prefix = (controller_prefix.length == 1) ? '' : controller_prefix + '/'
10
+ controller = File.basename(controller_file, ".rb")
11
+ controller_object = controller.camelize
12
+
13
+ model_prefix = controller_prefix.gsub(/^.*admin/,"").gsub(/^[\\\/]/, "")
14
+ model = controller.gsub("_controller","").singularize
15
+ model_object = model.camelize
16
+
17
+ if File.exist?( File.join(root_dir, 'app', 'models', model_prefix, model + '.rb') )
18
+ next if ['report'].include?(model)
19
+
20
+ #link_text = t(model + '.object_name').to_s.humanize
21
+ #link_text = t(model + '.object_name').to_s.humanize.pluralize
22
+ link_text = model.to_s.humanize.pluralize
23
+ controller_for_url = "#{controller_prefix}#{controller.gsub("_controller","")}"
24
+ action_for_url = 'index'
25
+
26
+ # Initialise section reference
27
+ section = self
28
+
29
+ controller_prefix.split(File::SEPARATOR).each do |sub_section|
30
+ if section[sub_section].nil?
31
+ section[sub_section] = Hash.new
32
+ #section[sub_section]['name'] = sub_section.to_s.humanize
33
+ end
34
+ section = section[sub_section]
35
+ end
36
+
37
+ section = Hash.new if section.nil?
38
+ section[controller] = Hash.new if section[controller].nil?
39
+ section[controller]['name'] = link_text
40
+ section[controller]['controller'] = controller_for_url
41
+ section[controller]['action'] = action_for_url
42
+ end
43
+ end
44
+ end
45
+
46
+ def depth(menu = self, count = 0)
47
+ count += 1
48
+
49
+ menu.each do |key, value|
50
+ break if value.class != Hash || value.has_key?('controller')
51
+
52
+ tmp_depth = depth(value, count)
53
+ count = tmp_depth if tmp_depth > count
54
+ end
55
+
56
+ count
57
+ end
58
+
59
+ def items
60
+ self
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ <% # Parameters :attribute => attribute, :klass_data => row_data %>
2
+ <%#= #render_attribute_value(attribute, klass_data) %>
3
+ <%#= #render_custom_fields(attribute, klass_data, @klass_info) %>
4
+
5
+ <%= render_attribute_value_and_custom_fields(attribute, klass_data, @klass_info) %>
@@ -0,0 +1,10 @@
1
+ <% if model && model.errors.any? %>
2
+ <div id="error_explanation">
3
+ <h2><%= pluralize(model.errors.count, "error") %> prohibited this <%= model.to_s %> from being saved:</h2>
4
+ <ul>
5
+ <% model.errors.full_messages.each do |message| %>
6
+ <li><%=message%></li>
7
+ <% end %>
8
+ </ul>
9
+ </div>
10
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%= stylesheet_link_tag 'crud/flash_notices', :media => 'screen' %>
2
+ <div class="clearthis">&nbsp;</div>
3
+ <% flash.each do |type, value| %>
4
+ <% unless flash.now[type.to_sym].blank? %>
5
+ <div id='flash-<%="#{type.to_s}"%>' class='flash_message flash_<%="#{type.to_s}"%>' >
6
+ <p><%= "#{value}" %></p>
7
+ </div>
8
+ <div class="clearthis">&nbsp;</div>
9
+ <% end %>
10
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <%= render 'error_messages', :model => @klass_data %>
2
+ <div class="actions">
3
+ <%= f.submit %>
4
+ </div>
5
+ <% @visible_attributes.each do |attribute| %>
6
+ <% unless ['id','created_at', 'updated_at'].include?(attribute[:column_name]) %>
7
+ <div class="field">
8
+ <%= f.label attribute[:column_name].to_sym %><br />
9
+ <% custom_fields = @klass_info.custom_fields(attribute[:column_name], controller.action_name.to_sym) %>
10
+ <% custom_fields_contain_a_replacement = @klass_info.custom_fields_contain_a_replacement(custom_fields) %>
11
+ <% unless custom_fields_contain_a_replacement %>
12
+ <%= edit_field_for_attribute(@klass_info, @klass_data, attribute, f).html_safe %>
13
+ <% end %>
14
+ <% custom_fields.each do |field| %>
15
+ <%= render field[:partial], {field[:record_data_parameter].to_sym => @klass_data}.merge(field[:additional_partial_parameters]) %><br/>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+ <% end %>
20
+ <div class="actions">
21
+ <%= f.submit %>
22
+ </div>
@@ -0,0 +1,117 @@
1
+ <div style="clear: both;"/>
2
+ <br />
3
+
4
+ <div style="clear: both;"/>
5
+ <% if is_allowed_to_update? %>
6
+ <%= link_to "New #{@klass_info[:name]}", new_path(:class_name => @klass_info[:name]) %>
7
+ <% end %>
8
+
9
+ <div style="clear: both;"/>
10
+ <br />
11
+
12
+ <div style="clear: both;"/>
13
+ <div id="crud_pagination" class="flickr_pagination" style="text-align: left; float: left; width: 75%;">
14
+ Items per page:
15
+ <%= select_tag :per_page, options_for_select([5, 10, 25, 50, 100], (controller.params[:per_page] ? controller.params[:per_page].to_i : 10)) %>
16
+ <br /><br />
17
+ <div id="upper_pagination_overlay" class="pagination_overlay" style="height: 16px;">
18
+ <%= will_paginate @klass_data %>
19
+ <%= hidden_field_tag :page, (controller.params[:page] ? controller.params[:page] : 1) %>
20
+ </div>
21
+ <br />
22
+ <%= page_entries_info @klass_data %>
23
+ <br /><br />
24
+ </div>
25
+ <div id="crud_search" style="text-align: right; float: right; width: 20%; min-width: 250px;">
26
+ <%= form_tag '#', :id => 'search_form', :method => :get do %>
27
+ Search:
28
+ <%= text_field_tag :search, ((controller.params[:search].nil? || controller.params[:search].empty?) ? @search_prompt : controller.params[:search]),
29
+ :value => ((controller.params[:search].nil? || controller.params[:search].empty?) ? @search_prompt : controller.params[:search]),
30
+ :style => ((controller.params[:search].nil? || controller.params[:search].empty?) ? 'color:#777;' : ''),
31
+ :onfocus => "if(this.value == '#{@search_prompt}') {this.style.color=''; this.value = '';}",
32
+ :onblur => "if(this.value == '') {this.style.color='#777'; this.value = '#{@search_prompt}';}"
33
+ -%>
34
+ <%= image_submit_tag 'crud/search-icon.png', { :height => '16' } %>
35
+ <br />
36
+ <% if false %>
37
+ <%= check_box_tag :crud_advanced_search, nil, ((controller.params[:advanced_search]=='true') ? true : false) %> <%= I18n.t(:advanced_search_prompt) %>
38
+ <% end %>
39
+ <% end %>
40
+ </div>
41
+ <div style="clear: both;"/>
42
+ <br />
43
+
44
+ <% if @klass_data.count > 0 %>
45
+ <table id="klass_table">
46
+ <thead>
47
+ <tr>
48
+ <% if false %>
49
+ <th></th>
50
+ <% end %>
51
+ <% @visible_attributes.each do |attribute| %>
52
+ <th>
53
+ <%= label(@klass_info[:name].to_sym, attribute[:column_name].to_sym) %>
54
+ <% if false %>
55
+ <%= "(#{attribute[:column_type]})" %>
56
+ <%= "#{attribute[:association].to_s} #{attribute[:association_class]}" if attribute[:association] %>
57
+ <% end %>
58
+ </th>
59
+ <% end %>
60
+ <% if is_allowed_to_view? %>
61
+ <th></th>
62
+ <% end %>
63
+ <% if is_allowed_to_update? %>
64
+ <th></th>
65
+ <th></th>
66
+ <th></th>
67
+ <% end %>
68
+ </tr>
69
+ </thead>
70
+ <tbody>
71
+ <% @klass_data.each do |row| %>
72
+ <tr style="background-color:<%= cycle("lightblue", "lightgrey") %>;">
73
+ <% if false %>
74
+ <td><%= check_box 'selected_items', row.attributes['id'], :id => nil %></td>
75
+ <% end %>
76
+ <% @visible_attributes.each do |attribute| %>
77
+ <td>
78
+ <%= render_attribute_value_and_custom_fields(attribute, row, @klass_info) %>
79
+ </td>
80
+ <% end %>
81
+ <% if is_allowed_to_view? %>
82
+ <td><%= link_to('Show', show_path(:class_name => @klass_info[:name], :id => row.id)) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
83
+ <% end %>
84
+ <% if is_allowed_to_update? %>
85
+ <td><%= link_to('Edit', edit_path(:class_name => @klass_info[:name], :id => row.id)) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
86
+ <td><%= link_to('Delete', delete_path(:class_name => @klass_info[:name], :id => row.id), :data => { :confirm => "Are you sure you want to delete '#{row}'?" }, :method => :delete) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
87
+ <td><%= link_to('Destroy', destroy_path(:class_name => @klass_info[:name], :id => row.id), :data => { :confirm => "Are you sure you want to destroy '#{row}'?" }, :method => :delete) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
88
+ <% end %>
89
+ </tr>
90
+ <% end %>
91
+ </tbody>
92
+ </table>
93
+
94
+ <br />
95
+
96
+ <div class="flickr_pagination" style="text-align: left;">
97
+ <%= page_entries_info @klass_data %>
98
+ <br /><br />
99
+ <div id="lower_pagination_overlay" class="pagination_overlay" style="height: 16px;">
100
+ <%= will_paginate @klass_data %>
101
+ </div>
102
+ </div>
103
+ <div style="clear: both;"/>
104
+ <br />
105
+ <% end # @klass_data.count > 0 %>
106
+
107
+ <% @klass_info.global_custom_fields(controller.action_name.to_sym).each do |field| %>
108
+ <%= render field[:partial], {field[:record_data_parameter].to_sym => @klass_data}.merge(field[:additional_partial_parameters]) %><br/>
109
+ <% end %>
110
+
111
+ <div style="clear: both;"/>
112
+ <% if is_allowed_to_update? %>
113
+ <%= link_to "New #{@klass_info[:name]}", new_path(:class_name => @klass_info[:name]) %>
114
+ <% end %>
115
+
116
+ <div style="clear: both;"/>
117
+ <br />
@@ -0,0 +1,17 @@
1
+ <h1><%= "Editing #{@klass_info[:name]}" %></h1>
2
+
3
+ <%= form_for(
4
+ @klass_data,
5
+ :as => @klass_info[:name_as_sym],
6
+ :url => update_path(:class_name => @klass_info[:name], :id => @klass_data.id),
7
+ :html => {:multipart => 'true'},
8
+ :method => :put
9
+ ) do |f| %>
10
+ <%= render 'form', :f => f %>
11
+ <% end %>
12
+
13
+ <% if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %>
14
+ <%= link_to 'Show', show_path(:class_name => @klass_info[:name], :id => @klass_data.id) %> |
15
+ <% end %>
16
+
17
+ <%= link_to "Back (List all #{@klass_info[:name].pluralize})", index_path(:class_name => @klass_info[:name]) %>
@@ -0,0 +1,6 @@
1
+ <%= stylesheet_link_tag "crud/pagination", :media => "all" %>
2
+ <%= javascript_include_tag "crud/pagination" %>
3
+ <h1><%= "Listing #{@klass_info[:name].pluralize}" %></h1>
4
+ <div id="klass_data" style="min-width: 1045px;">
5
+ <%= render('klass_data') %>
6
+ </div>
@@ -0,0 +1 @@
1
+ $("#klass_data").html("<%= escape_javascript(render("klass_data")) %>");
@@ -0,0 +1,13 @@
1
+ <h1><%= "New #{@klass_info[:name]}" %></h1>
2
+
3
+ <%= form_for(
4
+ @klass_data,
5
+ :as => @klass_info[:name_as_sym],
6
+ :url => create_path(:class_name => @klass_info[:name]),
7
+ :html => {:multipart => 'true'},
8
+ :method => :post
9
+ ) do |f| %>
10
+ <%= render 'form', :f => f %>
11
+ <% end %>
12
+
13
+ <%= link_to "Back (List all #{@klass_info[:name].pluralize})", index_path(:class_name => @klass_info[:name]) %>
@@ -0,0 +1,69 @@
1
+ <%= render 'error_messages', :model => @klass_data %>
2
+
3
+ <% @visible_attributes.each do |attribute| %>
4
+ <p>
5
+ <b><%= label(@klass_info[:name].to_sym, attribute[:column_name].to_sym) %>:</b>
6
+ <%= render_attribute_value_and_custom_fields(attribute, @klass_data, @klass_info) %>
7
+ </p>
8
+ <% end %>
9
+
10
+ <br/>
11
+
12
+ <% unless @klass_info[:has_one].empty? %>
13
+ <b>Has one:</b><br/>
14
+ <% @klass_info[:has_one].each do |association| %>
15
+ <% association_value = @klass_data.send("#{association[:association_name]}") %>
16
+ <%= "#{association[:association_name]}" %>
17
+ <% if association_value && ::Crud::KlassInfo.primary_key_is_id?(association_value.class) %>
18
+ [<%= link_to("#{association_value}", show_path(:class_name => association_value.class.name, :id => association_value.id)) %>]
19
+ <% end %>
20
+ <br/>
21
+ <% end %>
22
+ <% end %>
23
+
24
+ <% unless @klass_info[:has_many].empty? %>
25
+ <b>Has many:</b><br/>
26
+ <% @klass_info[:has_many].each do |association| %>
27
+ <% association_values = @klass_data.send("#{association[:association_name]}") %>
28
+ <%= "#{association[:association_name]}" %>
29
+ <% if association_values %>
30
+ <% association_values.each do |association_value| %>
31
+ <% if ::Crud::KlassInfo.primary_key_is_id?(association_value.class) %>
32
+ [<%= link_to("#{association_value}", show_path(:class_name => association_value.class.name, :id => association_value.id)) %>]
33
+ <% end %>
34
+ <% end %>
35
+ <% else %>
36
+ <%= "(0)" %>
37
+ <% end %>
38
+ <br/>
39
+ <% end %>
40
+ <% end %>
41
+
42
+ <% unless @klass_info[:has_and_belongs_to_many].empty? %>
43
+ <b>Has and belongs to many:</b><br/>
44
+ <% @klass_info[:has_and_belongs_to_many].each do |association| %>
45
+ <% association_values = @klass_data.send("#{association[:association_name]}") %>
46
+ <%= "#{association[:association_name]}" %>
47
+ <% if association_values %>
48
+ <% association_values.each do |association_value| %>
49
+ <% if ::Crud::KlassInfo.primary_key_is_id?(association_value.class) %>
50
+ [<%= link_to("#{association_value}", show_path(:class_name => association_value.class.name, :id => association_value.id)) %>]
51
+ <% end %>
52
+ <% end %>
53
+ <% else %>
54
+ <%= "(0)" %>
55
+ <% end %>
56
+ <br/>
57
+ <% end %>
58
+ <% end %>
59
+
60
+ <br/>
61
+
62
+ <% @klass_info.global_custom_fields(controller.action_name.to_sym).each do |field| %>
63
+ <%= render field[:partial], {field[:record_data_parameter].to_sym => @klass_data}.merge(field[:additional_partial_parameters]) %><br/>
64
+ <% end %>
65
+
66
+ <% if is_allowed_to_update? %>
67
+ <%= link_to 'Edit', edit_path(:class_name => @klass_info[:name], :id => @klass_data.id) %> |
68
+ <% end %>
69
+ <%= link_to "Back (List all #{@klass_info[:name].pluralize})", index_path(:class_name => @klass_info[:name]) %>
@@ -0,0 +1,15 @@
1
+ <%= stylesheet_link_tag "crud/dashboard", :media => "all" %>
2
+ <%= javascript_include_tag "crud/dashboard" %>
3
+ <h1>CRUD Dashboard</h1>
4
+ <h2>Select the class you wish to manipulate</h2>
5
+ <%= select_tag 'klass_list', options_for_select_tag, :prompt => 'Select a class' %><br/>
6
+ <h2>Model path:</h2>
7
+ <% Crud.model_path.each do |path_element| %>
8
+ <%= "#{path_element}" %><br/>
9
+ <% end %>
10
+ <% if false %>
11
+ <h2>Class list:</h2>
12
+ <% @klass_list.all.each do |klass| %>
13
+ <%= "#{klass.to_s}" %><br/>
14
+ <% end %>
15
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>CRUD</title>
5
+ <%= stylesheet_link_tag "crud/application", :media => "all" %>
6
+ <%= javascript_include_tag "crud/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body class="<%= (@klass_info ? 'crud_' + @klass_info[:name_as_sym].to_s : params[:controller].gsub('/','_')) %>">
10
+ <%= render 'crud/crud/flash_messages' %>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1,8 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %> features
7
+ wip: --tags @wip:3 --wip features
8
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip