awesome_form 0.0.1

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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +113 -0
  4. data/Rakefile +23 -0
  5. data/app/views/awesome_form/default_theme/actions/_default.html.haml +8 -0
  6. data/app/views/awesome_form/default_theme/inputs/_association.html.haml +14 -0
  7. data/app/views/awesome_form/default_theme/inputs/_boolean.html.haml +12 -0
  8. data/app/views/awesome_form/default_theme/inputs/_check_boxes.html.haml +18 -0
  9. data/app/views/awesome_form/default_theme/inputs/_default.html.haml +11 -0
  10. data/app/views/awesome_form/default_theme/inputs/_radios.html.haml +18 -0
  11. data/app/views/awesome_form/default_theme/inputs/_select.html.haml +18 -0
  12. data/app/views/awesome_form/default_theme/inputs/_text.html.haml +9 -0
  13. data/app/views/awesome_form/default_theme/wrappers/_actions.html.haml +2 -0
  14. data/app/views/awesome_form/default_theme/wrappers/_boolean.html.haml +4 -0
  15. data/app/views/awesome_form/default_theme/wrappers/_default.html.haml +4 -0
  16. data/app/views/awesome_form/default_theme/wrappers/_inputs.html.haml +2 -0
  17. data/config/routes.rb +2 -0
  18. data/lib/awesome_form.rb +36 -0
  19. data/lib/awesome_form/action_view_extensions/form_helper.rb +13 -0
  20. data/lib/awesome_form/engine.rb +4 -0
  21. data/lib/awesome_form/form_builder.rb +63 -0
  22. data/lib/awesome_form/methods/actions.rb +78 -0
  23. data/lib/awesome_form/methods/attributes.rb +117 -0
  24. data/lib/awesome_form/methods/inputs.rb +64 -0
  25. data/lib/awesome_form/methods/labels.rb +18 -0
  26. data/lib/awesome_form/methods/naming.rb +32 -0
  27. data/lib/awesome_form/methods/rendering.rb +44 -0
  28. data/lib/awesome_form/version.rb +3 -0
  29. data/lib/tasks/awesome_form_tasks.rake +4 -0
  30. data/spec/dummy/README.rdoc +28 -0
  31. data/spec/dummy/Rakefile +6 -0
  32. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  33. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  34. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  35. data/spec/dummy/app/controllers/forms_controller.rb +3 -0
  36. data/spec/dummy/app/controllers/sessions_controller.rb +2 -0
  37. data/spec/dummy/app/controllers/universes_controller.rb +2 -0
  38. data/spec/dummy/app/controllers/users_controller.rb +2 -0
  39. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  40. data/spec/dummy/app/models/session.rb +3 -0
  41. data/spec/dummy/app/models/universe.rb +3 -0
  42. data/spec/dummy/app/models/user.rb +5 -0
  43. data/spec/dummy/app/views/forms/actions.html.haml +2 -0
  44. data/spec/dummy/app/views/forms/blocks.html.haml +6 -0
  45. data/spec/dummy/app/views/forms/check_boxes.html.haml +4 -0
  46. data/spec/dummy/app/views/forms/data.html.haml +2 -0
  47. data/spec/dummy/app/views/forms/fields_for.html.haml +9 -0
  48. data/spec/dummy/app/views/forms/inputs.html.haml +8 -0
  49. data/spec/dummy/app/views/forms/radios.html.haml +4 -0
  50. data/spec/dummy/app/views/forms/selects.html.haml +9 -0
  51. data/spec/dummy/app/views/forms/wrappers.html.haml +3 -0
  52. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/spec/dummy/app/views/sessions/new.html.haml +7 -0
  54. data/spec/dummy/app/views/universes/new.html.haml +5 -0
  55. data/spec/dummy/app/views/users/new.html.haml +5 -0
  56. data/spec/dummy/bin/bundle +3 -0
  57. data/spec/dummy/bin/rails +4 -0
  58. data/spec/dummy/bin/rake +4 -0
  59. data/spec/dummy/config.ru +4 -0
  60. data/spec/dummy/config/application.rb +28 -0
  61. data/spec/dummy/config/boot.rb +5 -0
  62. data/spec/dummy/config/database.yml +25 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +29 -0
  65. data/spec/dummy/config/environments/production.rb +80 -0
  66. data/spec/dummy/config/environments/test.rb +36 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  69. data/spec/dummy/config/initializers/inflections.rb +16 -0
  70. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  71. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  72. data/spec/dummy/config/initializers/session_store.rb +3 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +23 -0
  75. data/spec/dummy/config/routes.rb +18 -0
  76. data/spec/dummy/db/development.sqlite3 +0 -0
  77. data/spec/dummy/db/migrate/20140108211716_create_users.rb +13 -0
  78. data/spec/dummy/db/migrate/20140108213444_create_universes.rb +11 -0
  79. data/spec/dummy/db/migrate/20140108214030_create_sessions.rb +10 -0
  80. data/spec/dummy/db/schema.rb +45 -0
  81. data/spec/dummy/db/test.sqlite3 +0 -0
  82. data/spec/dummy/log/development.log +14421 -0
  83. data/spec/dummy/log/test.log +84789 -0
  84. data/spec/dummy/public/404.html +58 -0
  85. data/spec/dummy/public/422.html +58 -0
  86. data/spec/dummy/public/500.html +57 -0
  87. data/spec/dummy/public/favicon.ico +0 -0
  88. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  89. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  90. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  91. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  92. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  93. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  94. data/spec/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  95. data/spec/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  96. data/spec/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  97. data/spec/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  98. data/spec/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  99. data/spec/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  100. data/spec/features/actions_generation_spec.rb +13 -0
  101. data/spec/features/awesome_form_for_spec.rb +25 -0
  102. data/spec/features/blocks_handling_spec.rb +16 -0
  103. data/spec/features/classes_spec.rb +14 -0
  104. data/spec/features/fields_discovery_spec.rb +34 -0
  105. data/spec/features/inputs_generation_spec.rb +73 -0
  106. data/spec/features/wrappers_generation_spec.rb +36 -0
  107. data/spec/spec_helper.rb +35 -0
  108. data/spec/support/dom/dom_expression.rb +62 -0
  109. data/spec/support/factories/universes.rb +5 -0
  110. data/spec/support/features/match_content_of.rb +6 -0
  111. data/spec/units/awesome_form_spec.rb +11 -0
  112. metadata +263 -0
@@ -0,0 +1,117 @@
1
+ module AwesomeForm
2
+ module Methods
3
+ module Attributes
4
+
5
+ def discover_attributes(model)
6
+ cols = association_columns(*AwesomeForm.default_associations)
7
+ cols += content_columns
8
+ cols -= AwesomeForm.excluded_columns.flatten.map(&:to_sym)
9
+ cols.compact
10
+ end
11
+
12
+ protected
13
+
14
+ def type_options_for_attribute(attribute, options)
15
+ type_options = {}
16
+ type_options[:type] = options.delete(:as).to_sym if options[:as].present?
17
+
18
+ column = column_for_attribute attribute
19
+ association = association_for_attribute attribute
20
+
21
+ if column.present?
22
+ type_options.reverse_merge! column_options_for(column)
23
+ elsif association.present?
24
+ type_options.reverse_merge! association_options_for(association)
25
+ else
26
+ type_options[:type] ||= type_for_string(attribute)
27
+ end
28
+
29
+ type_options.merge options
30
+ end
31
+
32
+ def type_for_string(attribute)
33
+ case attribute.to_s
34
+ when /password/ then :password
35
+ when /time_zone/ then :time_zone
36
+ when /country/ then :country
37
+ when /email/ then :email
38
+ when /phone/ then :tel
39
+ when /url/ then :url
40
+ else
41
+ # file_method?(attribute_name) ? :file : (input_type || :string)
42
+ :string
43
+ end
44
+ end
45
+
46
+ def column_for_attribute(attribute)
47
+ if @object.respond_to?(:column_for_attribute)
48
+ @object.column_for_attribute(attribute)
49
+ end
50
+ end
51
+
52
+ def association_for_attribute(attribute)
53
+ if @object.class.respond_to?(:reflect_on_association)
54
+ @object.class.reflect_on_association(attribute)
55
+ end
56
+ end
57
+
58
+ def column_options_for(column)
59
+ type = column.type
60
+
61
+ type = case type
62
+ when :string then type_for_string(column.name)
63
+ when :float, :integer then :number
64
+ else type
65
+ end
66
+
67
+ column_options = {
68
+ column_type: type,
69
+ type: type
70
+ }
71
+
72
+ column_options
73
+ end
74
+
75
+ def association_options_for(association)
76
+ association_options = {
77
+ type: :association,
78
+ association_type: association.macro,
79
+ multiple: association.instance_variable_get(:@collection),
80
+ collection: association.klass.all.map do |rec|
81
+ [ rec.try(:id), rec.try(:name) || rec.try(:to_s) ]
82
+ end
83
+ }
84
+
85
+ if association_options[:multiple]
86
+ association_options[:selected] = object.send(association.name).map(&:id)
87
+ else
88
+ association_options[:selected] = object.send(association.name) ? [object.send(association.name).try(:id)] : []
89
+ end
90
+
91
+ association_options
92
+ end
93
+
94
+ def content_columns()
95
+ klass = object.class
96
+ return [] unless klass.respond_to?(:content_columns)
97
+ klass.content_columns.collect { |c| c.name.to_sym }.compact
98
+ end
99
+
100
+ def association_columns(*by_associations)
101
+ if object.present? && object.class.respond_to?(:reflections)
102
+ object.class.reflections.collect do |name, association_reflection|
103
+ if by_associations.present?
104
+ if by_associations.include?(association_reflection.macro) && association_reflection.options[:polymorphic] != true
105
+ name
106
+ end
107
+ else
108
+ name
109
+ end
110
+ end.compact
111
+ else
112
+ []
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,64 @@
1
+ require 'awesome_form/methods/rendering'
2
+
3
+ module AwesomeForm
4
+ module Methods
5
+ module Inputs
6
+ extend AwesomeForm::Methods::Rendering
7
+
8
+ render_method :input
9
+
10
+ protected
11
+
12
+ def default_keys_for_inputs
13
+ discover_attributes(object)
14
+ end
15
+
16
+ def options_for_input(attribute, options)
17
+ type_options = type_options_for_attribute attribute, options
18
+
19
+ {
20
+ attribute_name: attribute,
21
+ object_name: object_name,
22
+ object: object,
23
+ builder: self,
24
+ }
25
+ .merge(type_options)
26
+ .merge(options)
27
+ .reverse_merge({
28
+ input_html: {}
29
+ })
30
+ end
31
+
32
+ def default_inputs_content(options)
33
+ content = ''
34
+ content << "<legend>#{options[:legend]}</legend>" if options[:legend].present?
35
+ content
36
+ end
37
+
38
+ def partial_for_input(input_options)
39
+ lookup_views partial_paths_for_input(input_options)
40
+ end
41
+
42
+ def wrapper_for_input(input_options)
43
+ partial_paths_for_input(input_options, :wrappers).select { |p| view_exists? p }.first
44
+ end
45
+
46
+ def partial_paths_for_input(input_options, scope=:inputs)
47
+ theme = AwesomeForm.theme
48
+
49
+ [
50
+ "awesome_form/#{scope}/#{resource_name}/#{input_options[:attribute_name]}",
51
+ "awesome_form/#{theme}/#{scope}/#{resource_name}/#{input_options[:attribute_name]}",
52
+
53
+ "awesome_form/#{scope}/#{input_options[:type]}",
54
+ "awesome_form/#{theme}/#{scope}/#{input_options[:type]}",
55
+ "awesome_form/default_theme/#{scope}/#{input_options[:type]}",
56
+
57
+ "awesome_form/#{scope}/default",
58
+ "awesome_form/#{theme}/#{scope}/default",
59
+ "awesome_form/default_theme/#{scope}/default"
60
+ ].uniq
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ module AwesomeForm
2
+ module Methods
3
+ module Labels
4
+
5
+ def input_label(attribute_name)
6
+ I18n.t("awesome_form.labels.#{resource_name}.#{attribute_name}", default: attribute_name.to_s.humanize)
7
+ end
8
+
9
+ def action_label(action)
10
+ I18n.t("awesome_form.actions.#{resource_name}.#{action}", {
11
+ default: I18n.t("awesome_form.actions.#{action}", {
12
+ default: action.to_s.humanize
13
+ })
14
+ })
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ module AwesomeForm
2
+ module Methods
3
+ module Naming
4
+
5
+ def input_name(attribute_name)
6
+ "#{object_name}[#{attribute_name}]"
7
+ end
8
+
9
+ def collection_name(attribute_name, index=nil)
10
+ "#{object_name}[#{attribute_name}][#{index}]"
11
+ end
12
+
13
+ def association_name(attribute_name)
14
+ reflection = association_for_attribute(attribute_name)
15
+
16
+ case reflection.macro
17
+ when :belongs_to then input_name "#{attribute_name}_id"
18
+ when :has_many then collection_name "#{attribute_name.to_s.singularize}_ids"
19
+ when :has_one
20
+ raise "Can't create the association name for a :has_one association"
21
+ else
22
+ raise "Unknown association #{reflection.macro}"
23
+ end
24
+ end
25
+
26
+ def input_id(attribute_name)
27
+ "#{object_name.underscore}_#{attribute_name}_input"
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,44 @@
1
+ module AwesomeForm
2
+ module Methods
3
+ module Rendering
4
+ def render_method(name)
5
+ plural = name.to_s.pluralize
6
+
7
+ class_eval <<-RUBY, __FILE__, __LINE__+1
8
+
9
+ def #{plural}(*args, &block)
10
+ keys, options = filter_arguments(*args)
11
+ keys = send("default_keys_for_#{plural}") if keys.empty?
12
+
13
+ theme = AwesomeForm.theme
14
+
15
+ paths = [
16
+ "awesome_form/wrappers/_#{plural}",
17
+ "awesome_form/" + theme.to_s + "/wrappers/_#{plural}",
18
+ "awesome_form/default_theme/wrappers/_#{plural}",
19
+ ]
20
+
21
+ text = default_#{plural}_content(options)
22
+ text << keys.map { |f| #{name} f, options }.join("\n").html_safe
23
+ text << @template.capture(self, &block) if block_given?
24
+
25
+ render text: text, layout: lookup_views(paths)
26
+ end
27
+
28
+ def #{name}(key, options={}, &block)
29
+ opts = send("options_for_#{name}", key, options)
30
+
31
+ render_options = {
32
+ partial: send("partial_for_#{name}", opts),
33
+ layout: send("wrapper_for_#{name}", opts),
34
+ locals: opts,
35
+ }
36
+ render render_options
37
+ end
38
+
39
+ RUBY
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module AwesomeForm
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :awesome_form do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Dummy::Application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,3 @@
1
+ class FormsController < ApplicationController
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ class SessionsController < ApplicationController
2
+ end
@@ -0,0 +1,2 @@
1
+ class UniversesController < ApplicationController
2
+ end
@@ -0,0 +1,2 @@
1
+ class UsersController < ApplicationController
2
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,3 @@
1
+ class Session < ActiveRecord::Base
2
+ belongs_to :user
3
+ end
@@ -0,0 +1,3 @@
1
+ class Universe < ActiveRecord::Base
2
+ has_many :users
3
+ end
@@ -0,0 +1,5 @@
1
+ class User < ActiveRecord::Base
2
+ belongs_to :universe
3
+
4
+ accepts_nested_attributes_for :universe
5
+ end
@@ -0,0 +1,2 @@
1
+ = awesome_form_for User.new, url: '#' do |form|
2
+ = form.actions :submit, :reset
@@ -0,0 +1,6 @@
1
+ = awesome_form_for User.new, url: '#' do |form|
2
+ = form.inputs :name do
3
+ = form.input :email
4
+
5
+ = form.actions do
6
+ = form.action :submit
@@ -0,0 +1,4 @@
1
+ = awesome_form_for User.new, url: '#', method: :get do |form|
2
+ = form.input :foo, as: :check_boxes, collection: ['foo', 'bar']
3
+
4
+ = form.actions
@@ -0,0 +1,2 @@
1
+ = awesome_form_for User.new, url: '#' do |form|
2
+ = form.input :foo, input_html: { data: { id: 1, type: 'Universe' } }
@@ -0,0 +1,9 @@
1
+ :ruby
2
+ user = User.new name: 'irrelevant'
3
+ user.universe = Universe.new name: 'irrelevant'
4
+
5
+ = awesome_form_for user, url: '' do |form|
6
+ = form.input :name
7
+
8
+ = form.fields_for :universe do |universe_form|
9
+ = universe_form.input :name
@@ -0,0 +1,8 @@
1
+ = awesome_form_for User.new, url: '#' do |form|
2
+ = form.input :foo, as: :text
3
+ = form.input :foo, as: :string, input_html: { value: 'bar' }
4
+ = form.input :foo, as: :number, input_html: { min: 1, max: 10, step: 1, value: 5 }
5
+ = form.input :foo, as: :range, input_html: { min: 1, max: 10, step: 1, value: 5}
6
+ = form.input :foo, as: :datetime, input_html: { min: 1.day.ago, max: 1.day.from_now, value: Time.now }
7
+ = form.input :foo, as: :checkbox, input_html: { value: 1, checked: true }
8
+ = form.input :foo, as: :file
@@ -0,0 +1,4 @@
1
+ = awesome_form_for User.new, url: '#', method: :get do |form|
2
+ = form.input :foo, as: :radios, collection: ['foo', 'bar']
3
+
4
+ = form.actions