motr 0.0.1 → 0.0.2

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.
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"