motr 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -7,5 +7,7 @@ gem "rspec-rails"
7
7
  gem "mocha","0.9.12"
8
8
 
9
9
  group :test do
10
+ gem 'fabrication', '0.9.5'
11
+ gem 'ffaker', '1.5.0'
10
12
  gem 'spork', '~> 0.9.0.rc'
11
13
  end
@@ -2,6 +2,7 @@ module MotrHelper #:nodoc:
2
2
 
3
3
  include Motr::Helpers::LayoutHelpers
4
4
  include Motr::Helpers::Navigation
5
- include Motr::Forms::Helpers
5
+ include Motr::Helpers::Elements
6
+ include Motr::Forms::Helpers
6
7
 
7
8
  end
@@ -7,6 +7,7 @@ module Motr
7
7
  module Helpers
8
8
  autoload :LayoutHelpers, 'motr/helpers/layout_helpers'
9
9
  autoload :Navigation, 'motr/helpers/navigation'
10
+ autoload :Elements, 'motr/helpers/elements'
10
11
  end
11
12
 
12
13
  module Errors
@@ -1,12 +1,14 @@
1
- module Motr #:nodoc
2
- module Errors #:nodoc
1
+ module Motr
2
+ module Errors
3
3
 
4
4
  # Default parent Motr error for all custom errors. This handles the base
5
5
  # key for the translations and provides the convenience method for
6
6
  # translating the messages.
7
+ #
7
8
  class MotrError < StandardError
8
9
  BASE_KEY = "motr.errors"
9
- ##
10
+
11
+ # ##
10
12
  # Translate an error message
11
13
  # @param [String] key The i18n message key
12
14
  # @param [Hash] options Options to pass to the i18n library
@@ -26,6 +26,27 @@ module Motr
26
26
  mattr_accessor :default_builder
27
27
  @@default_builder = Motr::Forms::Builder
28
28
 
29
+ # Stub out a new default_error_proc, but create the option to override it if necessary
30
+ mattr_accessor :field_error_proc
31
+ @@field_error_proc = lambda{ |html_tag, instance_tag| html_tag }
32
+
33
+ protected
34
+
35
+ ##
36
+ #
37
+ # Wrapper method to override the default field_error_proc
38
+ # Field errors are displayed using the template defined by Motr::Forms.error_template
39
+ #
40
+ # @return [String]
41
+ #
42
+ def self.with_custom_error_proc(&block)
43
+ default_proc = ::ActionView::Base.field_error_proc
44
+ ::ActionView::Base.field_error_proc = Motr::Forms.field_error_proc
45
+ yield
46
+ ensure
47
+ ::ActionView::Base.field_error_proc = default_proc
48
+ end
49
+
29
50
  end
30
51
 
31
52
  end
@@ -2,14 +2,202 @@ module Motr
2
2
 
3
3
  module Forms
4
4
 
5
+ ##
6
+ # Base class for creating form builders
7
+ #
5
8
  class Base < ActionView::Helpers::FormBuilder
6
9
 
7
- def render_field_with_errors(html_tag, messages)
10
+ # Access the template object
11
+ attr_accessor :template
12
+ # Tracks the order in which fields are used in the form, this allows the easy rebuilding of the submitted form
13
+ # data when submitted since normally the hash isn't ordered.
14
+ attr_accessor :field_order
15
+ # Tracks the field currently being "processed"
16
+ attr_accessor :current_field_type
17
+
18
+
19
+ # Overrides fields_for to make sure the form builder is set properly
20
+ def fields_for(record_or_name_or_array, *args, &block) #:nodoc:
21
+ opts = args.extract_options!
22
+ opts[:builder] ||= Motr::Forms.default_builder
23
+ args.push(opts)
24
+ Motr::Forms.with_custom_error_proc do
25
+ super(record_or_name_or_array, *args, &block)
26
+ end
27
+ end
28
+
29
+
30
+ protected
31
+
32
+ ##
33
+ #
34
+ # Checks to see if a particular attribute is required, if so, a "required" attribute is added to the field.
35
+ #
36
+ # @param [Symbol] attribute The attribute to check against validators
37
+ # @return [Boolean]
38
+ #
39
+ def attribute_required?(attribute)
40
+ validates_presence?(attribute) || validates_inclusion?(attribute)
41
+ end
42
+
43
+ # Convenience method to use the +content_tag+ method from our template
44
+ #
45
+ def content_tag(tag, content, options = {}, escape = true, &block) #:nodoc:
46
+ @template.content_tag(tag, content, options, escape, &block)
47
+ end
48
+
49
+ ##
50
+ # Checks to see if there are errors for the particular method or attribute
51
+ #
52
+ # @param [Symbol] method The method/attribute to check
53
+ #
54
+ # @return [Boolean]
55
+ #
56
+ def errors_on_attribute?(method)
57
+ !(@object.nil? || @object.errors.empty? || !@object.errors.key?(method.to_sym) || [@object.errors[method.to_sym]].flatten.empty?)
58
+ end
59
+
60
+ ##
61
+ #
62
+ # Checks a passed validator to see if it is required
63
+ # 'borrowed' from Formtastic by Justin French (see https://github.com/justinfrench/formtastic)
64
+ #
65
+ # @param [Hash] options Validator options
66
+ #
67
+ def options_require_validation?(options)
68
+
69
+ allow_blank = options[:allow_blank]
70
+ return !allow_blank unless allow_blank.nil?
71
+ if_condition = !options[:if].nil?
72
+ condition = if_condition ? options[:if] : options[:unless]
73
+
74
+ condition = if condition.respond_to?(:call)
75
+ condition.call(@object)
76
+ elsif condition.is_a?(::Symbol) && @object.respond_to?(condition)
77
+ @object.send(condition)
78
+ else
79
+ condition
80
+ end
81
+ if_condition ? !!condition : !condition
82
+ end
83
+
84
+ ##
85
+ #
86
+ # Wrapper method used by all form fields to customize the output
87
+ #
88
+ # @param [Symbol] helper_method Original Rails helper method name
89
+ # @param [Symbol] method Object method / symbol used for the element
90
+ # @param [Array] args Array of original arguments passed to the helper
91
+ #
92
+ # @return [String] Rendered HTML tag for the element
93
+ #
94
+ def render_field_as_custom(helper_method, method, *args)
95
+
96
+ @current_field_type = helper_method
97
+
98
+ options = args.extract_options!
99
+ (@field_order ||= []) << method
100
+
101
+ # Add an error class to the field if it has errors
102
+ #
103
+ if errors_on_attribute?(method)
104
+ klasses = (options.delete(:class) || "").split(" ")
105
+ klasses << Motr::Forms.error_class
106
+ options[:class] = klasses.join(" ")
107
+ end
108
+
109
+ # Add a required attribute to the field if it is required
110
+ # Skip if false was passed as the required option
111
+ #
112
+ options[:required] = "required" if attribute_required?(method) && options[:required].to_s != 'false'
113
+ options['data-validates-uniqueness'] = "true" if validates_uniqueness?(method)
114
+
115
+ result = send(:"_super_#{helper_method}", method, *(args << options))
116
+ render_field_with_errors(method, result, @object.errors[method])
117
+
118
+ end
119
+
120
+ ##
121
+ #
122
+ # Renders the passed +html_tag+ with the custom error_template
123
+ # @see Motr::Forms#error_template
124
+ #
125
+ # @param [Symbol] method The method/attribute to check for errors
126
+ # @param [Object, String] html_tag Instance of an input tag or a string
127
+ # @param [Array] messages An array of all error messages to be added to the template
128
+ #
129
+ def render_field_with_errors(method, html_tag, messages)
130
+
131
+ return html_tag unless errors_on_attribute?(method)
132
+
8
133
  error_class = Motr::Forms.error_class
9
134
  message_error_class = Motr::Forms.message_error_class
10
135
  render_binding = binding
11
136
  renderer = ERB.new(Motr::Forms.error_template)
137
+
12
138
  renderer.result(render_binding).to_s.html_safe
139
+
140
+ end
141
+
142
+ ##
143
+ #
144
+ # Compiles an array of all validators for a particular attribute
145
+ # @param [Symbol] attribtue The attribute to check
146
+ #
147
+ def validators_for(attribute)
148
+
149
+ return [] if @object.nil?
150
+ return [] unless @object.class.respond_to?(:validators_on)
151
+
152
+ attribute = attribute.to_s.sub(/_id$/, '').to_sym
153
+ @object.class.validators_on(attribute).uniq
154
+
155
+ end
156
+
157
+ ##
158
+ #
159
+ # Convenience method to see if a particular attribute has validators
160
+ # @param [Symbol] attribute The attribute to check
161
+ #
162
+ def validators_for?(attribute)
163
+ !validators_for(attribute).empty?
164
+ end
165
+
166
+ ##
167
+ #
168
+ # Checks for a presence validation on a particular attribute
169
+ # @param [Symbol] attribute The attribute to check
170
+ #
171
+ def validates_presence?(attribute)
172
+ validator_of_type_exists?(validators_for(attribute), :presence)
173
+ end
174
+
175
+ ##
176
+ #
177
+ # Checks for a uniqueness validation on a particular attribute
178
+ # @param [Symbol] attribute The attribute to check
179
+ #
180
+ def validates_uniqueness?(attribute)
181
+ validator_of_type_exists?(validators_for(attribute), :uniqueness, false)
182
+ end
183
+
184
+ ##
185
+ #
186
+ # Checks for inclusion validation on a particular attribute
187
+ # @param [Symbol] attribute The attribute to check
188
+ #
189
+ def validates_inclusion?(attribute)
190
+ validator_of_type_exists?(validators_for(attribute), :inclusion)
191
+ end
192
+
193
+ private
194
+
195
+ def validator_of_type_exists?(validators, kind, check_options = true) #:nodoc:
196
+ validators.detect do |validator|
197
+ exists = (validator.kind.to_s == kind.to_s)
198
+ next exists unless (check_options && exists) && validator.options.present?
199
+ options_require_validation?(validator.options)
200
+ end
13
201
  end
14
202
 
15
203
  end
@@ -8,18 +8,54 @@ module Motr
8
8
  #
9
9
  class Builder < Motr::Forms::Base
10
10
 
11
- # Access the template object
12
- attr_accessor :template
13
- # Tracks the order in which fields are used in the form, this allows the easy rebuilding of the submitted form
14
- # data when submitted since normally the hash isn't ordered.
15
- attr_accessor :field_order
11
+ # create overrides for custom rendering
12
+ [:email_field, :password_field, :text_field, :text_area, :url_field, ].each do |method|
13
+ class_eval <<-FUNC, __FILE__, __LINE__ + 1
14
+
15
+ alias :_super_#{method} :#{method}
16
+
17
+ def #{method}(method_name, *args)
18
+ render_field_as_custom(:#{method}, method_name, *args)
19
+ end
20
+ FUNC
21
+ end
16
22
 
17
- private
23
+ ##
24
+ # Modified label tag to support adding a 'required' asterisk to the end of the label
25
+ #
26
+ def label(method, text = nil, options = {}, &block)
27
+
28
+ options, text = text, nil if text.is_a?(Hash)
29
+ text ||= method.to_s.humanize
30
+
31
+ options.stringify_keys!
32
+ klasses = (options.delete([:class]) || "").split(" ")
33
+ klasses << Motr::Forms.error_class if errors_on_attribute?(method)
34
+ options[:class] = klasses.join(" ") unless klasses.compact.empty?
35
+
36
+ text = "#{text} <abbr title='Required'>*</abbr>".html_safe if attribute_required?(method)
37
+ super(method, text, options, &block)
38
+
39
+ end
18
40
 
19
- # Convenience method to use the +content_tag+ method from our template
41
+ ##
42
+ #
43
+ # Creates a button tag to be used in a form instead of the default submit
44
+ # This makes CSS styling easier
45
+ #
46
+ # @param [String] value The text for the button
47
+ # @param [Hash] options HTML options to be passed to the button
48
+ # @option [String] icon If included, adds an image to the button to be used as an icon
20
49
  #
21
- def content_tag(tag, content, options = {}, escape = true, &block) #:nodoc:
22
- @template.content_tag(tag, content, options, escape, &block)
50
+ def button(value = nil, options = {})
51
+
52
+ value, options = nil, value if value.is_a?(Hash)
53
+ value ||= submit_default_value
54
+
55
+ value = [image_tag(icon, :class => 'icon'), value].join(' ') if icon = options.delete(:icon)
56
+
57
+ content_tag(:button, value.to_s.html_safe, options.reverse_merge!({ "type" => "submit", "name" => "commit" }))
58
+
23
59
  end
24
60
 
25
61
  end
@@ -9,20 +9,26 @@ module Motr
9
9
  ##
10
10
  #
11
11
  # Cusomizes the default form_for helper to add additional functionality
12
- # (see ActionView::Helpers::FormHelper for more information)
12
+ # All params are the same as Rails' form_for
13
13
  #
14
- # @option options [Boolean] :validate Adds a data-validatable attribute to the form for javascript hooks
14
+ # @param [Mixed] record_name_or_array
15
+ # @param [Array] args
16
+ # @param [Block] &block
15
17
  #
16
- def motr_form(record, options = {}, &block)
18
+ def motr_form(record_name_or_array, *args, &proc)
17
19
 
18
20
  raise ArgumentError, "Missing block" unless block_given?
19
21
 
22
+ options = args.extract_options!
20
23
  options.reverse_merge!(:builder => Motr::Forms.default_builder)
21
24
  options[:html] ||= {}
22
25
  options[:html].merge!('data-validatable' => true) if options.delete(:validate)
23
- form_for(record, options, &block)
24
-
25
- end
26
+
27
+ Motr::Forms.with_custom_error_proc do
28
+ form_for(record_name_or_array, *(args << options), &proc)
29
+ end
30
+
31
+ end
26
32
 
27
33
  end
28
34
 
@@ -0,0 +1,74 @@
1
+ module Motr
2
+ module Helpers
3
+ ##
4
+ #
5
+ # Generates misc html elements that aren't included in Rails core, or are custom.
6
+ #
7
+ module Elements
8
+
9
+ ##
10
+ # Generates a "button" link tag. Simply a convenience method to skip adding 'class="button"' and also adds an +icon+ option
11
+ # @see Motr::Forms::Builder#button For form related buttons
12
+ #
13
+ # @param [String] txt The link text
14
+ # @param [String] path The link href
15
+ # @param [Types] Name Description
16
+ #
17
+ # @example Create a plain link.button
18
+ # button_link('Blog', '/blog') #=> <a href="/blog" class="button">Blog</a>
19
+ # @example Create a link.button with icon
20
+ # button_link('Blog', '/blog', :icon => 'blog_image.png') #=> <a href="/blog" class="button"><img src="/images/blog_image.png" alt="Blog" /> Blog</a>
21
+
22
+ def button_link(txt, path, attrs = {}, incl_span = false)
23
+ image = attrs.delete(:icon)
24
+ klasses = (attrs.delete(:class) || "").split(" ")
25
+ klasses << 'button'
26
+ klasses = klasses.uniq.compact
27
+ content = ""
28
+ content << image_tag(image) unless image.nil?
29
+ content << (incl_span ? "<span>#{txt}</span>" : txt)
30
+ link_to content.html_safe, path, attrs.merge(:class => klasses.join(" "))
31
+ end
32
+
33
+ ##
34
+ #
35
+ # Convenience method for outputting all current flash messages. This allows you to avoid
36
+ # using things like "if flash[:success]" and so on, which is far from DRY
37
+ #
38
+ # @param [Hash] attrs Options to modify the html attributes and settings
39
+ # @option attrs [Symbol] closer Specify HTML to be appended to the message in case you want a "close" button/link. Defaults to "<span>X</span>"
40
+ # @option attrs [Symbol] wrapper Specify the HTML element which wraps each message. Defaults to :div
41
+ #
42
+ # @example Output any available flash messages, appending a "closer" span
43
+ # In your controller:
44
+ # flash[:success] = "You did something awesome"
45
+ # In your view or layout
46
+ # <%= flash_messages :close => "<span>X</span>" %> #=> <div class="flash_message flash_message_success success">You did something awesome <span>X</span></div>
47
+ #
48
+ # @example Output a message without a "close"
49
+ # <%= flash_messages :close => false %> #=> <div class="flash_message flash_message_success success">You did something awesome</div>
50
+ #
51
+ #
52
+ def flash_messages(attrs = {})
53
+
54
+ wrapper = attrs.delete(:wrapper) || :div
55
+ closer = attrs.delete(:closer)
56
+ closer ||= "<span>X</span>" unless closer === false
57
+ klasses = (attrs.delete(:class) || "").split(" ")
58
+ klasses << "flash_message"
59
+ content = ""
60
+
61
+ flash.each_key do |k|
62
+ klasses << "flash_message_#{k.to_s.underscore}"
63
+ msg_attrs = attrs.merge(:class => [k.to_s, klasses].flatten.join(' '))
64
+ content.concat content_tag(wrapper, "#{flash[k]} #{closer}", msg_attrs)
65
+ end
66
+
67
+ content.html_safe
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
@@ -1,7 +1,11 @@
1
1
  module Motr
2
- class Engine < ::Rails::Engine
2
+ class Engine < ::Rails::Engine #:nodoc:
3
3
  config.motr = Motr
4
4
 
5
+ # Add load paths straight to I18n, so engines and application can overwrite it.
6
+ require 'active_support/i18n'
7
+ I18n.load_path << File.expand_path('../../config/locales/en.yml', __FILE__)
8
+
5
9
  initializer :after_initialize do
6
10
  ActionView::Base.send :default_form_builder=, Motr::Forms.default_builder
7
11
  end
@@ -1,3 +1,3 @@
1
- module Motr
2
- VERSION = "0.0.1"
1
+ module Motr #:nodoc:
2
+ VERSION = "0.0.2".freeze
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: motr
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Brent Kirby
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-30 00:00:00 -04:00
13
+ date: 2011-05-02 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -58,8 +58,30 @@ dependencies:
58
58
  prerelease: false
59
59
  version_requirements: *id004
60
60
  - !ruby/object:Gem::Dependency
61
- name: activemodel
61
+ name: fabrication
62
62
  requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - "="
66
+ - !ruby/object:Gem::Version
67
+ version: 0.9.5
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: ffaker
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - "="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.5.0
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: activemodel
84
+ requirement: &id007 !ruby/object:Gem::Requirement
63
85
  none: false
64
86
  requirements:
65
87
  - - ~>
@@ -67,10 +89,10 @@ dependencies:
67
89
  version: "3.0"
68
90
  type: :runtime
69
91
  prerelease: false
70
- version_requirements: *id005
92
+ version_requirements: *id007
71
93
  - !ruby/object:Gem::Dependency
72
94
  name: rails
73
- requirement: &id006 !ruby/object:Gem::Requirement
95
+ requirement: &id008 !ruby/object:Gem::Requirement
74
96
  none: false
75
97
  requirements:
76
98
  - - ~>
@@ -78,7 +100,7 @@ dependencies:
78
100
  version: "3.0"
79
101
  type: :runtime
80
102
  prerelease: false
81
- version_requirements: *id006
103
+ version_requirements: *id008
82
104
  description: motr is a Rails engine aimed at simplifying routine development. The core motr engine includes various helpers, utilities, and modifications to rails core.
83
105
  email:
84
106
  - dev@kurbmedia.com
@@ -97,6 +119,7 @@ files:
97
119
  - lib/motr/forms/builder.rb
98
120
  - lib/motr/forms/helpers.rb
99
121
  - lib/motr/forms.rb
122
+ - lib/motr/helpers/elements.rb
100
123
  - lib/motr/helpers/layout_helpers.rb
101
124
  - lib/motr/helpers/navigation.rb
102
125
  - lib/motr/rails.rb
@@ -120,7 +143,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
143
  requirements:
121
144
  - - ">="
122
145
  - !ruby/object:Gem::Version
123
- hash: 1164898289255422466
146
+ hash: -1045787232198311107
124
147
  segments:
125
148
  - 0
126
149
  version: "0"