message_block 1.0

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/CHANGELOG.rdoc ADDED
@@ -0,0 +1,9 @@
1
+ == [2010-10-13] 1.0 Major Updates
2
+
3
+ * Finally updated to be a Gem
4
+ * Internal refactoring
5
+ * Converted tests to RSpec
6
+ * New cucumber features
7
+ * Added support for Rails 3.0
8
+
9
+ == 0.1.0 Initial Beta Version
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Ben Hughes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,126 @@
1
+ == Message Block
2
+
3
+ Implements the common view pattern by which a list of messages are shown at the top,
4
+ often a combination of flash messages and ActiveRecord validation issues on one or more models.
5
+ This allows for a nice, stylized block of messages at the top of the page with icons
6
+ indicating what type of message it is (error, confirmation, warning, etc.)
7
+
8
+ This view helper acts as a replacement for error_messages_for by taking error messages
9
+ from your models and combing them with flash messages (multiple types such as error, confirm, etc.)
10
+ and outputting them to your view. This plugin comes with an example stylesheet and images.
11
+
12
+ == Installation
13
+
14
+ Include the gem using bundler in your Gemfile:
15
+
16
+ gem "message_block"
17
+
18
+ Then run the rake task to install the static files:
19
+
20
+ rake message_block:install
21
+
22
+ == Usage
23
+
24
+ Once you install this, you should now have a set of images at public/images/message_block and
25
+ a basic stylesheet installed at public/stylesheets/message_block.css. First you'll want to either
26
+ reference this in your layout or copy the declarations to your main layout. Then you can use
27
+ the helper <tt><%= message_block %></tt> as described below:
28
+
29
+ The first argument specifies a hash options:
30
+
31
+ * <tt>:on</tt> - specifies one or many model names for which to check error messages.
32
+ * <tt>:model_error_type</tt> - specifies the message type to use for validation errors; defaults to 'error'
33
+ * <tt>:flash_types</tt> - specifies the keys to check in the flash hash. Messages will be grouped in ul
34
+ lists according to this type. Defaults to: %w(back confirm error info warn)
35
+ * <tt>:html</tt> - Specifies HTML options for the containing div
36
+ * <tt>:id</tt> - Specifies ID of the containing div; defaults to 'message_block'
37
+ * <tt>:class</tt> - Specifies class name of the containing div; defaults to nothing.
38
+ * <tt>:container</tt> - specifies which block-level element to contain the errors (defaults to :div).
39
+
40
+ === Example
41
+ Imagine you have a form for entering a user and a comment:
42
+
43
+ <%= message_block :on => [:user, :comment] %>
44
+
45
+ Imagine also you set these flash variables in the controller:
46
+ class CommentsController
47
+ def create
48
+ flash.now[:error] = "Error A"
49
+ flash.now[:confirm] = "Confirmation A" # Note you can use different types
50
+ flash.now[:warn] = ["Warn A", "Warn B"] # Can set to an array for multiple messages
51
+ end
52
+ end
53
+
54
+ And let's say that you want to show these messages but also show the validation issues
55
+ given that both user and comment fail ActiveRecord validation:
56
+
57
+ <div id="message_block" class="message_block">
58
+ <ul class="error">
59
+ <li>Error A</li>
60
+ <li>User first name is required.</li>
61
+ <li>Comment contents is required.</li>
62
+ </ul>
63
+ <ul class="confirm">
64
+ <li>Confirmation A</li>
65
+ </ul>
66
+ <ul class="warn">
67
+ <li>Warn A</li>
68
+ <li>Warn B</li>
69
+ </ul>
70
+ </div>
71
+
72
+ === Ajax & JavaScript Integration
73
+
74
+ Sometimes you'll want to use the message block pattern within JavaScript. Wouldn't it be nice to just populate
75
+ the message_block DOM tree based on a JavaScript object not unlike Rails flash?
76
+
77
+ Included in the plugin is a Prototype JS implementation to make this easier. Note that this file is *not* automatically
78
+ copied when the plugin is installed. Currently only a Prototype version is available (jQuery coming soon!)
79
+
80
+ assets/javascripts/message_block_prototype.js
81
+
82
+ Example Usage:
83
+
84
+ <div id="something">
85
+ <%= message_block :on => :job %>
86
+ </div>
87
+
88
+ <script type="text/javascript">
89
+ document.observe('dom:loaded', function() {
90
+ message_block = new MessageBlock('message_block'); // Default ID is message_block, being explicit
91
+
92
+ // Updates with two errors and one confirmation
93
+ message_block.update({
94
+ error: ['Error One', 'Error Two'],
95
+ confirm: ['Confirmation Message']
96
+ });
97
+
98
+ // Clears the message block
99
+ message_block.clear();
100
+
101
+ // Same as above...
102
+ message_block.update({});
103
+ });
104
+ </script>
105
+
106
+ This could be useful if you're interacting with stuff via Ajax, for example:
107
+
108
+ # In Controller
109
+ wants.json do
110
+ render :status => :unprocessable_entity, :json => { 'error' => @job.errors.full_messages }
111
+ end
112
+
113
+ # JavaScript Ajax
114
+ new Ajax.Request("/jobs", {
115
+ method: 'get',
116
+
117
+ onFailure: function(transport) {
118
+ this.message_block.update(transport.responseJSON);
119
+ },
120
+
121
+ onSuccess: function(transport) {
122
+ this.message_block.clear();
123
+
124
+ // Do something...
125
+ }
126
+ });
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/rdoctask'
4
+ require 'spec/rake/spectask'
5
+
6
+ desc "Run specs"
7
+ Spec::Rake::SpecTask.new do |t|
8
+ t.spec_files = Rake::FileList["spec/**/*_spec.rb"]
9
+ t.spec_opts = ["-c"]
10
+ end
11
+
12
+ task :default => :spec
13
+
14
+ desc "Generate documentation for the plugin."
15
+ Rake::RDocTask.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = "rdoc"
17
+ rdoc.title = "message_block"
18
+ rdoc.options << "--line-numbers" << "--inline-source"
19
+ rdoc.rdoc_files.include('README')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Dir["#{File.dirname(__FILE__)}/lib/tasks/*.rake"].sort.each { |ext| load ext }
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "message_block"
@@ -0,0 +1,54 @@
1
+ module MessageBlock
2
+ module Helpers
3
+
4
+ def message_block(options = {})
5
+ options.assert_valid_keys(:on, :model_error_type, :flash_types, :html, :id, :class, :container)
6
+
7
+ options[:model_error_type] ||= :error
8
+ options[:flash_types] ||= [:notice, :back, :confirm, :error, :info, :warn].sort_by(&:to_s)
9
+ options[:on] ||= controller.controller_name.split('/').last.gsub(/\_controller$/, '').singularize.to_sym
10
+ options[:html] ||= {:id => "message_block", :class => "message_block"}
11
+ options[:html][:id] = options[:id] if options[:id]
12
+ options[:html][:class] = options[:class] if options[:class]
13
+ options[:container] = :div if options[:container].nil?
14
+
15
+ flash_messages = {}
16
+
17
+ options[:flash_types].each do |type|
18
+ entries = flash[type.to_sym]
19
+ next if entries.nil?
20
+ entries = [entries] unless entries.is_a?(Array)
21
+
22
+ flash_messages[type.to_sym] ||= []
23
+ flash_messages[type.to_sym] += entries
24
+ end
25
+
26
+ options[:on] = [options[:on]] unless options[:on].is_a?(Array)
27
+
28
+ options[:on] = [options[:on]] unless options[:on].is_a?(Array)
29
+ model_objects = options[:on].map do |model_object|
30
+ if model_object.instance_of?(String) or model_object.instance_of?(Symbol)
31
+ instance_variable_get("@#{model_object}")
32
+ else
33
+ model_object
34
+ end
35
+ end.select {|m| !m.nil? }
36
+
37
+ model_errors = model_objects.inject([]) {|b, m| b += m.errors.full_messages }
38
+
39
+ flash_messages[options[:model_error_type].to_sym] ||= []
40
+ flash_messages[options[:model_error_type].to_sym] += model_errors
41
+
42
+ contents = flash_messages.keys.sort_by(&:to_s).select {|type| !flash_messages[type.to_sym].empty? }.map do |type|
43
+ "<ul class=\"#{type}\">" + flash_messages[type.to_sym].map {|message| "<li>#{message}</li>" }.join + "</ul>"
44
+ end.join
45
+
46
+ if options[:container]
47
+ content_tag(options[:container], contents, options[:html], false)
48
+ else
49
+ contents
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,21 @@
1
+ module MessageBlock
2
+ if defined?(Rails::Railtie)
3
+ class Railtie < Rails::Railtie
4
+ initializer "message_block.insert_helpers" do
5
+ ActiveSupport.on_load(:action_view) do
6
+ MessageBlock::Railtie.insert
7
+ end
8
+ end
9
+
10
+ rake_tasks do
11
+ load "tasks/message_block.rake"
12
+ end
13
+ end
14
+ end
15
+
16
+ class Railtie
17
+ def self.insert
18
+ ActionView::Base.send(:include, MessageBlock::Helpers)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ require "rubygems"
2
+ require "active_support"
3
+ require "message_block/helpers"
4
+ require "message_block/railtie"
@@ -0,0 +1,36 @@
1
+ namespace :message_block do
2
+ desc "Installs static files for the message_block gem"
3
+ task :install do
4
+ puts "Copying assets..."
5
+
6
+ images_source = File.join(File.dirname(__FILE__), "..", "..", "assets", "images")
7
+ stylesheets_source = File.join(File.dirname(__FILE__), "..", "..", "assets", "stylesheets", "message_block.css")
8
+ javascripts_source = File.join(File.dirname(__FILE__), "..", "..", "assets", "javascripts", "message_block.js")
9
+
10
+ images_target = Rails.root.join("public", "images", "message_block")
11
+ stylesheets_target = Rails.root.join("public", "stylesheets", "message_block.css")
12
+ javascripts_target = Rails.root.join("public", "javascripts", "message_block.js")
13
+
14
+ unless File.exists?(images_target)
15
+ FileUtils.cp_r(images_source, images_target)
16
+ puts " Copied Images"
17
+ else
18
+ puts " Images appear to already be installed, not copying."
19
+ end
20
+
21
+ unless File.exists?(stylesheets_target)
22
+ FileUtils.cp(stylesheets_source, stylesheets_target)
23
+ puts " Copied Stylesheet"
24
+ else
25
+ puts " Stylesheet appears to already be installed, not copying"
26
+ end
27
+
28
+ unless File.exists?(javascripts_target)
29
+ FileUtils.cp(javascripts_source, javascripts_target)
30
+ puts " Copied Javascript"
31
+ else
32
+ puts " Javascript appears to already be installed, not copying"
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,124 @@
1
+ require "spec_helper"
2
+
3
+ describe MessageBlock::Helpers do
4
+ include ActionView::Helpers::TagHelper
5
+ include MessageBlock::Helpers
6
+
7
+ before do
8
+ setup_post
9
+ setup_user
10
+ end
11
+
12
+ it "should not accept invalid options" do
13
+ lambda { message_block :invalid => "option" }.should raise_error(ArgumentError)
14
+ end
15
+
16
+ it "should accept valid options" do
17
+ lambda {
18
+ message_block :on => :post,
19
+ :model_error_type => "fail",
20
+ :flash_types => %w(error warn),
21
+ :html => {:style => 'height: 10em'},
22
+ :id => "block",
23
+ :class => "messages"
24
+ }.should_not raise_error
25
+ end
26
+
27
+ it "should show nothing with no errors" do
28
+ message_block.should == %(<div class="message_block" id="message_block"></div>)
29
+ end
30
+
31
+ it "should automatically find post errorts with posts controller" do
32
+ @controller = posts_controller
33
+ output = message_block
34
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>Author name can't be empty</li></ul></div>)
35
+ end
36
+
37
+ it "should give no error for post" do
38
+ output = message_block(:on => :post)
39
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>Author name can't be empty</li></ul></div>)
40
+ end
41
+
42
+ it "should give error for user" do
43
+ output = message_block(:on => :user)
44
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>User email can't be empty</li></ul></div>)
45
+ end
46
+
47
+ it "should give errors for both post and user" do
48
+ output = message_block(:on => [:post, :user])
49
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>Author name can't be empty</li><li>User email can't be empty</li></ul></div>)
50
+ end
51
+
52
+ it "should give errors for both post and user in the correct order" do
53
+ output = message_block(:on => [:user, :post])
54
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>)
55
+ end
56
+
57
+ it "should give error for user given direct instance variable" do
58
+ output = message_block(:on => @user)
59
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>User email can't be empty</li></ul></div>)
60
+ end
61
+
62
+ it "should respect model error type" do
63
+ output = message_block(:on => :user, :model_error_type => "fail")
64
+ output.should == %(<div class="message_block" id="message_block"><ul class="fail"><li>User email can't be empty</li></ul></div>)
65
+ end
66
+
67
+ it "should be able to specify id for containing div" do
68
+ output = message_block(:id => "messages")
69
+ output.should == %(<div class="message_block" id="messages"></div>)
70
+ end
71
+
72
+ it "should be able to specify class for containing div" do
73
+ output = message_block(:class => "messages")
74
+ output.should == %(<div class="messages" id="message_block"></div>)
75
+ end
76
+
77
+ it "should be able to specify html options for containing div" do
78
+ output = message_block(:html => {:id => "block", :class => "messages"})
79
+ output.should == %(<div class="messages" id="block"></div>)
80
+ end
81
+
82
+ it "should be able to specify container option as false" do
83
+ output = message_block(:on => :post, :container => false)
84
+ output.should == %(<ul class="error"><li>Author name can't be empty</li></ul>)
85
+ end
86
+
87
+ it "should be able to specify container option" do
88
+ output = message_block(:on => :post, :container => :fieldset)
89
+ output.should == %(<fieldset class="message_block" id="message_block"><ul class="error"><li>Author name can't be empty</li></ul></fieldset>)
90
+ end
91
+
92
+ it "should be able to see flash error string" do
93
+ flash[:error] = "Error A"
94
+ output = message_block
95
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>Error A</li></ul></div>)
96
+ end
97
+
98
+ it "should be able to see flash error array" do
99
+ flash[:error] = ["Error A", "Error B"]
100
+ output = message_block
101
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>Error A</li><li>Error B</li></ul></div>)
102
+ end
103
+
104
+ it "should be able to see default flash types" do
105
+ default_types = [:notice, :back, :confirm, :error, :info, :warn].sort_by(&:to_s)
106
+ default_types.each do |type|
107
+ flash[type] = type.to_s
108
+ end
109
+
110
+ expected_contents = default_types.map do |type|
111
+ content_tag(:ul, content_tag(:li, type.to_s), :class => type.to_s)
112
+ end.join
113
+
114
+ output = message_block
115
+ output.should == %(<div class="message_block" id="message_block">#{expected_contents}</div>)
116
+ end
117
+
118
+ it "should be able to see flash error alongside model error" do
119
+ flash[:error] = "Error A"
120
+ output = message_block(:on => :post)
121
+ output.should == %(<div class="message_block" id="message_block"><ul class="error"><li>Error A</li><li>Author name can't be empty</li></ul></div>)
122
+ end
123
+
124
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format nested
3
+ --loadby mtime
4
+ --reverse
5
+ --backtrace
@@ -0,0 +1,74 @@
1
+ require "rubygems"
2
+ require "spec"
3
+ require "active_support"
4
+ require "action_view"
5
+ require "message_block"
6
+
7
+ require File.dirname(__FILE__) + '/../init'
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.mock_with :mocha
11
+ end
12
+
13
+ # Borrowed model stubs from Rails active_record_helper_test.rb
14
+ # TODO: Re-implement using mocha
15
+ Post = Struct.new("Post", :title, :author_name)
16
+ User = Struct.new("User", :email)
17
+
18
+ def setup_post
19
+ @post = Post.new
20
+ def @post.errors
21
+ Class.new do
22
+ def on(field)
23
+ case field.to_s
24
+ when "author_name"
25
+ "can't be empty"
26
+ when "body"
27
+ true
28
+ else
29
+ false
30
+ end
31
+ end
32
+ def empty?() false end
33
+ def count() 1 end
34
+ def full_messages() [ "Author name can't be empty" ] end
35
+ end.new
36
+ end
37
+
38
+ @post.title = "Hello World"
39
+ @post.author_name = ""
40
+ end
41
+
42
+ def setup_user
43
+ @user = User.new
44
+ def @user.errors
45
+ Class.new {
46
+ def on(field) field == "email" end
47
+ def empty?() false end
48
+ def count() 1 end
49
+ def full_messages() [ "User email can't be empty" ] end
50
+ }.new
51
+ end
52
+
53
+ @user.email = ""
54
+ end
55
+
56
+ def controller
57
+ @controller ||= Class.new {
58
+ def controller_name
59
+ "widgets_controller"
60
+ end
61
+ }.new
62
+ end
63
+
64
+ def posts_controller
65
+ Class.new {
66
+ def controller_name
67
+ "posts_controller"
68
+ end
69
+ }.new
70
+ end
71
+
72
+ def flash
73
+ @flash ||= {}
74
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: message_block
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ version: "1.0"
10
+ platform: ruby
11
+ authors:
12
+ - Ben Hughes
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-14 00:00:00 +08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activesupport
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 5
29
+ segments:
30
+ - 2
31
+ - 2
32
+ - 1
33
+ version: 2.2.1
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: actionpack
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 5
45
+ segments:
46
+ - 2
47
+ - 2
48
+ - 1
49
+ version: 2.2.1
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: Implements the common view pattern by which a list of messages are shown at the top, often a combination of flash messages and ActiveRecord validation issues on one or more models.
53
+ email: ben@railsgarden.com
54
+ executables: []
55
+
56
+ extensions: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ files:
61
+ - lib/message_block/helpers.rb
62
+ - lib/message_block/railtie.rb
63
+ - lib/message_block.rb
64
+ - lib/tasks/message_block.rake
65
+ - spec/message_block/helpers_spec.rb
66
+ - spec/spec.opts
67
+ - spec/spec_helper.rb
68
+ - CHANGELOG.rdoc
69
+ - LICENSE
70
+ - Rakefile
71
+ - README.rdoc
72
+ - init.rb
73
+ has_rdoc: true
74
+ homepage: http://github.com/rubiety/message_block
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options: []
79
+
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 19
97
+ segments:
98
+ - 1
99
+ - 3
100
+ - 4
101
+ version: 1.3.4
102
+ requirements: []
103
+
104
+ rubyforge_project: message_block
105
+ rubygems_version: 1.3.7
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Flash message and error_messages_for handling with a common interface.
109
+ test_files: []
110
+