diff --git a/lib/proto-mysql2/app.rb b/lib/proto-mysql2/app.rb
new file mode 100644
index 00000000..75c5fc8e
--- /dev/null
+++ b/lib/proto-mysql2/app.rb
@@ -0,0 +1,10 @@
+# This file contains your application, it requires dependencies and necessary
+# parts of the application.
+require 'rubygems'
+require 'ramaze'
+
+# Make sure that Ramaze knows where you are
+Ramaze.options.roots = [__DIR__]
+
+require __DIR__('model/init')
+require __DIR__('controller/init')
diff --git a/lib/proto-mysql2/controller/main.rb b/lib/proto-mysql2/controller/main.rb
new file mode 100644
index 00000000..a795d026
--- /dev/null
+++ b/lib/proto-mysql2/controller/main.rb
@@ -0,0 +1,30 @@
+# Default url mappings are:
+#
+# * a controller called Main is mapped on the root of the site: /
+# * a controller called Something is mapped on: /something
+#
+# If you want to override this, add a line like this inside the class:
+#
+# map '/otherurl'
+#
+# this will force the controller to be mounted on: /otherurl.
+class MainController < Controller
+ # the index action is called automatically when no other action is specified
+ def index
+ @title = 'Welcome to Ramaze!'
+ begin
+ @database = DB["select database() as db"].first
+ rescue => e
+ @database = {:db => nil, :error => e.to_s}
+ end
+ end
+
+ # the string returned at the end of the function is used as the html body
+ # if there is no template for the action. if there is a template, the string
+ # is silently ignored
+ def notemplate
+ @title = 'Welcome to Ramaze!'
+
+ return 'There is no \'notemplate.xhtml\' associated with this action.'
+ end
+end
diff --git a/lib/proto-mysql2/database.yml b/lib/proto-mysql2/database.yml
new file mode 100644
index 00000000..8374e0ee
--- /dev/null
+++ b/lib/proto-mysql2/database.yml
@@ -0,0 +1,34 @@
+dev:
+ adapter: {adapter}
+ host: {server}
+ database: {dbname}
+ username: {username}
+ password: {password}
+ encoding: utf8
+ reconnect: false
+ port: 3306
+
+# Other Options (See https://github.com/brianmario/mysql2/blob/master/README.md)
+# socket: '/path/to/mysql.sock'
+# flags: REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION | MULTI_STATEMENTS
+# encoding: 'utf8'
+# read_timeout: seconds
+# write_timeout: seconds
+# connect_timeout: seconds
+# reconnect: true/false
+# local_infile: true/false
+# secure_auth: true/false
+# default_file: '/path/to/my.cfg'
+# default_group: 'my.cfg section'
+# init_command => sql
+
+live:
+ adapter: {adapter}
+ host: {server}
+ database: {dbname}
+ username: {username}
+ password: {password}
+ encoding: utf8
+ reconnect: false
+ port: 3306
+
diff --git a/lib/proto-mysql2/model/init.rb b/lib/proto-mysql2/model/init.rb
new file mode 100644
index 00000000..7bccae54
--- /dev/null
+++ b/lib/proto-mysql2/model/init.rb
@@ -0,0 +1,15 @@
+# Open the database
+require 'ramaze'
+require 'mysql2'
+require 'sequel'
+require 'yaml'
+
+# open up the appropriate database and log it
+Host = YAML.load_file("#{Ramaze.options.roots[0]}/database.yml")[ENV['MODE']]
+DB = Sequel.connect(Host)
+Ramaze::Log.info "Database \"#{Host['database']}\" opened"
+
+# Require all models in the models folder
+Dir.glob('model/*.rb').each do |model|
+ require("#{Ramaze.options.roots[0]}/#{model}")
+end
diff --git a/lib/proto-mysql2/view/index.xhtml b/lib/proto-mysql2/view/index.xhtml
new file mode 100644
index 00000000..ec9ae75f
--- /dev/null
+++ b/lib/proto-mysql2/view/index.xhtml
@@ -0,0 +1,55 @@
+
+
+ Congratulations, Ramaze is running fine and your database "#{@database[:db]}" is open on MySQL.
+ You can start working on your application.
+
+ Sorry, but your database isn't working properly.
+ The error message MySQL returned was:
+ #{@database[:error]}.
+
+
+
+
+ You can play around with this prototype by changing the following:
+
+
+
+
+ view/index.xhtml: the content of this page.
+
+
+ layout/default.xhtml: the layout for this page.
+
+
+ controller/main.rb: the controller responsible for server this page.
+
+ Feel free to post to the
+ Ramaze Google Group, your
+ first mail has to go through moderation, so please be patient.
+
diff --git a/lib/proto-sqlite/app.rb b/lib/proto-sqlite/app.rb
new file mode 100644
index 00000000..75c5fc8e
--- /dev/null
+++ b/lib/proto-sqlite/app.rb
@@ -0,0 +1,10 @@
+# This file contains your application, it requires dependencies and necessary
+# parts of the application.
+require 'rubygems'
+require 'ramaze'
+
+# Make sure that Ramaze knows where you are
+Ramaze.options.roots = [__DIR__]
+
+require __DIR__('model/init')
+require __DIR__('controller/init')
diff --git a/lib/proto-sqlite/controller/main.rb b/lib/proto-sqlite/controller/main.rb
new file mode 100644
index 00000000..a4421d6c
--- /dev/null
+++ b/lib/proto-sqlite/controller/main.rb
@@ -0,0 +1,30 @@
+# Default url mappings are:
+#
+# * a controller called Main is mapped on the root of the site: /
+# * a controller called Something is mapped on: /something
+#
+# If you want to override this, add a line like this inside the class:
+#
+# map '/otherurl'
+#
+# this will force the controller to be mounted on: /otherurl.
+class MainController < Controller
+ # the index action is called automatically when no other action is specified
+ def index
+ @title = 'Welcome to Ramaze!'
+ begin
+ @database = DB["select random() as db"].first
+ rescue => e
+ @database = {:db => nil, :error => e.to_s}
+ end
+ end
+
+ # the string returned at the end of the function is used as the html body
+ # if there is no template for the action. if there is a template, the string
+ # is silently ignored
+ def notemplate
+ @title = 'Welcome to Ramaze!'
+
+ return 'There is no \'notemplate.xhtml\' associated with this action.'
+ end
+end
diff --git a/lib/proto-sqlite/database.yml b/lib/proto-sqlite/database.yml
new file mode 100644
index 00000000..28191671
--- /dev/null
+++ b/lib/proto-sqlite/database.yml
@@ -0,0 +1,8 @@
+dev:
+ adapter: {adapter}
+ database: {dbname}
+
+live:
+ adapter: {adapter}
+ database: {dbname}
+
diff --git a/lib/proto-sqlite/model/init.rb b/lib/proto-sqlite/model/init.rb
new file mode 100644
index 00000000..8e586fc3
--- /dev/null
+++ b/lib/proto-sqlite/model/init.rb
@@ -0,0 +1,15 @@
+# Open the database
+require 'ramaze'
+require 'sqlite3'
+require 'sequel'
+require 'yaml'
+
+# open up the appropriate database and log it
+Host = YAML.load_file("#{Ramaze.options.roots[0]}/database.yml")[ENV['MODE']]
+DB = Sequel.connect("#{Host['adapter']}://#{Host['database']}")
+Ramaze::Log.info "Database \"#{Host['database']}\" opened"
+
+# Require all models in the models folder
+Dir.glob('model/*.rb').each do |model|
+ require("#{Ramaze.options.roots[0]}/#{model}")
+end
diff --git a/lib/proto-sqlite/view/index.xhtml b/lib/proto-sqlite/view/index.xhtml
new file mode 100644
index 00000000..4b303f35
--- /dev/null
+++ b/lib/proto-sqlite/view/index.xhtml
@@ -0,0 +1,55 @@
+
+
+ Congratulations, Ramaze is running fine and your database is open on MySQL.
+ You can start working on your application.
+
+ Sorry, but your database isn't working properly.
+ The error message MySQL returned was:
+ #{@database[:error]}.
+
+
+
+
+ You can play around with this prototype by changing the following:
+
+
+
+
+ view/index.xhtml: the content of this page.
+
+
+ layout/default.xhtml: the layout for this page.
+
+
+ controller/main.rb: the controller responsible for server this page.
+
+ Feel free to post to the
+ Ramaze Google Group, your
+ first mail has to go through moderation, so please be patient.
+
diff --git a/lib/proto/controller/init.rb b/lib/proto/controller/init.rb
index 0725c9bc..43a82eb7 100644
--- a/lib/proto/controller/init.rb
+++ b/lib/proto/controller/init.rb
@@ -8,11 +8,7 @@ class Controller < Ramaze::Controller
engine :etanni
end
-# Here you can require all your other controllers. Note that if you have multiple
-# controllers you might want to do something like the following:
-#
-# Dir.glob('controller/*.rb').each do |controller|
-# require(controller)
-# end
-#
-require __DIR__('main')
+# Require all controllers in the controllers folder
+Dir.glob('controller/*.rb').each do |controller|
+ require("#{Ramaze.options.roots[0]}/#{controller}")
+end
diff --git a/lib/ramaze/bin/create.rb b/lib/ramaze/bin/create.rb
index 953e1a9f..c5e891bb 100644
--- a/lib/ramaze/bin/create.rb
+++ b/lib/ramaze/bin/create.rb
@@ -1,4 +1,5 @@
require 'fileutils'
+require 'sequel'
module Ramaze
#:nodoc:
@@ -14,6 +15,9 @@ module Bin
# @author Yorick Peterse
# @since 21-07-2011
#
+ # @author Michael J. Welch, Ph.D.
+ # @since 17-05-2016
+ #
class Create
Description = 'Creates a new Ramaze application'
@@ -25,7 +29,9 @@ class Create
ramaze create [NAME] [OPTIONS]
Example:
- ramaze create blog
+ ramaze create --help # this message
+ ramaze create blog # create a project named blog
+ ramaze create blog -a mysql2 -d blog_dev -u bloguser -p dFLaWp3uts97pFwcdz7 # same, but with database
TXT
##
@@ -35,9 +41,17 @@ class Create
# @author Yorick Peterse
# @since 21-07-2011
#
+ # @author Michael J. Welch, Ph.D.
+ # @since 17-05-2016
+ #
def initialize
@options = {
- :force => false
+ :force => false,
+ :adapter => nil,
+ :server => 'localhost',
+ :dbname => 'your_dbname',
+ :username => 'your_username',
+ :password => 'your_password'
}
@opts = OptionParser.new do |opt|
@@ -46,12 +60,32 @@ def initialize
opt.separator "\nOptions:\n"
+ opt.on('-a', '--adapter adapter', 'Specifies the database adapter name [no default]') do |adapter|
+ @options[:adapter] = adapter
+ end
+
+ opt.on('-s', '--server server', 'Specifies the database server(host) name [default: localhost]') do |server|
+ @options[:server] = server
+ end
+
+ opt.on('-d', '--dbname dbname', 'Specifies the database dbname [default: your_dbname]') do |dbname|
+ @options[:dbname] = dbname
+ end
+
+ opt.on('-u', '--username username', 'Specifies the database username [default: your_username]') do |username|
+ @options[:username] = username
+ end
+
+ opt.on('-p', '--password password', 'Specifies the database password [default: your_password]') do |password|
+ @options[:password] = password
+ end
+
opt.on('-f', '--force', 'Overwrites existing directories') do
@options[:force] = true
end
opt.on('-h', '--help', 'Shows this help message') do
- puts @opts
+ puts @opts.to_s
exit
end
end
@@ -68,10 +102,12 @@ def run(argv = [])
@opts.parse!(argv)
path = argv.delete_at(0)
- proto = __DIR__('../../proto')
-
abort 'You need to specify a name for your application' if path.nil?
+ proto = __DIR__('../../proto')
+ proto_adapter = if @options[:adapter] then "#{proto}-#{@options[:adapter]}" else nil end
+ abort "The #{@options[:adapter]} adapter is not supported--See the documentation" if proto_adapter && Dir[proto_adapter].empty?
+
if File.directory?(path) and @options[:force] === false
abort 'The specified application already exists, use -f to overwrite it'
end
@@ -82,9 +118,24 @@ def run(argv = [])
begin
FileUtils.cp_r(proto, path)
+
+ if proto_adapter
+ # copy whatever is in the proto-adapter directory
+ FileUtils.cp_r(Dir.glob("#{proto_adapter}/**"), path)
+
+ # update the database.yml file in the new project
+ yml = nil
+ File::open("#{path}/database.yml",'r') { |f| yml = f.read }
+ [:adapter, :server, :dbname, :username, :password].each do |opt|
+ yml.gsub!("{#{opt.to_s}}",@options[opt])
+ end
+ File::open("#{path}/database.yml",'w') { |f| yml = f.write(yml) }
+ end
+
puts "The application has been generated and saved in #{path}"
- rescue
- abort 'The application could not be generated'
+ rescue => e
+ puts e.backtrace[0..5]
+ abort "#{e}\nThe application could not be generated"
end
end
end # Create
diff --git a/lib/ramaze/bin/runner.rb b/lib/ramaze/bin/runner.rb
index ff73150d..356fbf16 100644
--- a/lib/ramaze/bin/runner.rb
+++ b/lib/ramaze/bin/runner.rb
@@ -34,7 +34,10 @@ module Runner
ramaze [COMMAND] [OPTIONS]
Example:
- ramaze create blog
+ ramaze --help # this message
+ ramaze create -h # help for the create command
+ ramaze create blog # create a project named blog
+ ramaze create blog -a mysql2 -d blog_dev -u bloguser -p dFLaWp3uts97pFwcdz7 # same, but with database
TXT
##
@@ -50,6 +53,7 @@ module Runner
# ARGV by default.
#
def self.run(argv=ARGV)
+ help = false
op = OptionParser.new do |opt|
opt.banner = Banner
opt.summary_indent = ' '
@@ -65,9 +69,9 @@ def self.run(argv=ARGV)
exit
end
+ # Show the help message
opt.on('-h', '--help', 'Shows this help message') do
- puts op
- exit
+ help = true
end
end
@@ -85,7 +89,12 @@ def self.run(argv=ARGV)
cmd = Commands[cmd].new
cmd.run(argv)
else
- abort 'The specified command is invalid'
+ if help
+ puts op
+ exit
+ else
+ abort 'The specified command is invalid'
+ end
end
end
diff --git a/lib/ramaze/gestalt.rb b/lib/ramaze/gestalt.rb
index caa1ee03..a7981c97 100644
--- a/lib/ramaze/gestalt.rb
+++ b/lib/ramaze/gestalt.rb
@@ -69,11 +69,39 @@ def p(*args, &block)
end
##
- # Workaround for Kernel#select to make work.
+ # Workaround for @g.table in BlueForm using method/call.
+ # This is needed in order to use m = g.method("table") etc.
#
- # @param [Array] args Extra arguments that should be processed before
- # creating the select tag.
- # @param [Proc] block
+ def table(*args, &block)
+ _gestalt_call_tag :table, args, &block
+ end
+
+ ##
+ # Workaround for @g.tr in BlueForm using method/call.
+ # This is needed in order to use m = g.method("tr") etc.
+ #
+ def tr(*args, &block)
+ _gestalt_call_tag :tr, args, &block
+ end
+
+ ##
+ # Workaround for @g.th in BlueForm using method/call.
+ # This is needed in order to use m = g.method("th") etc.
+ #
+ def th(*args, &block)
+ _gestalt_call_tag :th, args, &block
+ end
+
+ ##
+ # Workaround for @g.td in BlueForm using method/call.
+ # This is needed in order to use m = g.method("td") etc.
+ #
+ def td(*args, &block)
+ _gestalt_call_tag :td, args, &block
+ end
+
+ ##
+ # Workaround for Kernel#select to make work.
#
def select(*args, &block)
_gestalt_call_tag(:select, args, &block)
@@ -137,7 +165,7 @@ def _gestalt_escape_entities(s)
end
##
- # Shortcut for building tags,
+ # Shortcut for building tags.
#
# @param [String] name
# @param [Array] args
@@ -147,6 +175,15 @@ def tag(name, *args, &block)
_gestalt_call_tag(name.to_s, args, &block)
end
+ ##
+ # A way to append text to the output of Gestalt.
+ #
+ # @param [String] text
+ #
+ def <<(str)
+ @out << str
+ end
+
##
# Convert the final output of Gestalt to a string.
# This method has the following alias: "to_str".
@@ -157,5 +194,56 @@ def to_s
@out.join
end
alias to_str to_s
+
+ ##
+ # Method used for converting the results of the Gestalt helper to a
+ # human readable string. This isn't recommended for production because
+ # it requires much more time to generate the HTML output than to_s.
+ #
+ # @return [String] The formatted form output
+ #
+ def to_html
+ # Combine the sub-parts to form whole tags or whole in-between texts
+ parts = []
+ tag = ""
+ @out.each do |frag|
+ fragment = String.new(frag)
+ case
+ when fragment[0] == '<'
+ if tag.empty?
+ tag << fragment
+ else
+ parts << tag
+ tag = fragment
+ end
+ when fragment[-1] == '>'
+ tag << fragment
+ parts << tag
+ tag = ""
+ else
+ tag << fragment
+ end # case
+ end
+ parts << tag if tag
+ # output the segments, but adjust the indentation
+ indent = 0
+ html = ""
+ parts.each do |part|
+ case
+ when part[0..1] == ''
+ indent -= 1
+ end
+ html << "#{' '*indent}#{part}\n"%indent
+ case
+ when (part[0] == '<') && (part[-2..-1] == '/>')
+ # self terminating tag -- no change in indent
+ when (part[0] == '<') && (part[1] != '/')
+ indent += 1
+ end
+ end
+ # return the formatted string
+ return html
+ end # to_html
+
end # Gestalt
end # Ramaze
diff --git a/lib/ramaze/helper/blue_form.rb b/lib/ramaze/helper/blue_form.rb
index 5560be1e..a252eabc 100644
--- a/lib/ramaze/helper/blue_form.rb
+++ b/lib/ramaze/helper/blue_form.rb
@@ -23,6 +23,7 @@ module Helper
#
# form_for(@data, :method => :post) do |f|
# f.input_text 'Username', :username
+ # f.input_password 'Password', :password
# end
#
# The object comes handy when you want to do server-side form validation:
@@ -82,15 +83,29 @@ module BlueForm
# called using a block and it's return value should be manually sent to
# the browser (since it does not echo the value).
#
- # @param [Object] form_values Object containing the values for each form
- # field.
+ # @param [Object] form_object Object containing the values for each form
+ # field. If the object contains a hash of the form {:field=>"error"} it
+ # will be used to generate error messages in the BlueForm output.
# @param [Hash] options Hash containing any additional form attributes
- # such as the method, action, enctype and so on.
+ # such as the method, action, enctype and so on. To choose an
+ # arrangement of paragraph, table, or none, use
+ # :arrangement=>:paragraph, et.al.
# @param [Block] block Block containing the elements of the form such as
# password fields, textareas and so on.
#
- def form_for(form_values, options = {}, &block)
- form = Form.new(form_values, options)
+ def form_for(form_object, options = {}, &block)
+ form = Form.new(form_object, options)
+ case
+ when form_object.nil?
+ # There is no form object, therefore, no errors
+ when !form_object.respond_to?(:errors)
+ # There is a form object, but it has no errors field
+ when !form_object.errors.is_a?(Hash)
+ # There is an errors object, but it's not a Hash so ignore it
+ else
+ # There is a form object, and it has a Hash errors field
+ form_errors.merge!(form_object.errors)
+ end
form.build(form_errors, &block)
form
end
@@ -145,6 +160,47 @@ def form_errors_from_model(obj)
end
end
+ ##
+ # Class BlueFormModel contains a mass copy method like Sequel's that
+ # can be used to create objects for 'form_for' that are not
+ # database models, but have this one mass assignment
+ # method in them.
+ #
+ # @example
+ # class Login < BlueFormModel
+ # :attr_accessor :username, :password, :confirm
+ # end
+ #
+ # login = Login.new
+ # login.set_fields(session.request.params, [:username,:password,:confirm])
+ #
+ # @caveat
+ # Any use of 'BlueFormModel' must FOLLOW the 'helper :blue_form'
+ # statement in your code (which loads it).
+ #
+ class BlueFormModel
+ attr_accessor :errors
+ def initialize
+ @errors = {}
+ end
+ def valid?
+ @errors.empty?
+ end
+ def set_fields(hash, fields, opts={})
+ fields.each do |f|
+ if hash.has_key?(f)
+ instance_variable_set("@#{f}", hash[f])
+ elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
+ instance_variable_set("@#{sf}", hash[sf])
+ else
+ raise NoMethodError.new("undefined method `#{f.to_s}=' for #{self.inspect}") \
+ if opts[:missing]!=:skip
+ end
+ end
+ self
+ end
+ end
+
##
# Main form class that contains all the required methods to generate form
# specific tags, such as textareas and select boxes. Do note that this
@@ -153,20 +209,29 @@ def form_errors_from_model(obj)
#
class Form
attr_reader :g
- attr_reader :form_values
+ attr_reader :form_object
##
# Constructor method that generates an instance of the Form class.
#
- # @param [Object] form_values Object containing the values for each form
+ # @param [Object] form_object Object containing the values for each form
# field.
# @param [Hash] options A hash containing any additional form attributes.
# @return [Object] An instance of the Form class.
#
- def initialize(form_values, options)
- @form_values = form_values
+ def initialize(form_object, options)
+ @form_object = form_object
+ @arrangement = options.delete(:arrangement)
+ @arrangement = :paragraph if ([:table,:paragraph,:none].index(@arrangement)).nil?
@form_args = options.dup
- @g = Gestalt.new
+ @g = Ramaze::Gestalt.new
+ end
+
+ ##
+ # Placeholder when no wrapper tag is used
+ #
+ def nul(*args)
+ yield
end
##
@@ -181,16 +246,31 @@ def build(form_errors = {})
@form_errors = {}
form_errors.each do |key, value|
- if value.respond_to?(:first)
- value = value.first
- end
-
+ value = value.first if value.respond_to?(:first)
@form_errors[key.to_s] = value
end
@g.form(@form_args) do
if block_given?
- yield self
+ case @arrangement
+ when :paragraph
+ @table_wrapper = self.method('nul')
+ @paragraph_wrapper = @g.method('p')
+ @label_wrapper = self.method('nul')
+ @input_wrapper = self.method('nul')
+ when :table
+ @table_wrapper = @g.method('table')
+ @paragraph_wrapper = @g.method('tr')
+ @label_wrapper = @g.method('th')
+ @input_wrapper = @g.method('td')
+ when :none
+ @table_wrapper = self.method('nul')
+ @paragraph_wrapper = self.method('nul')
+ @label_wrapper = self.method('nul')
+ @input_wrapper = self.method('nul')
+ end
+ @hidden_wrapper = self.method('nul')
+ @table_wrapper.call { yield(self) }
end
end
end
@@ -224,87 +304,22 @@ def fieldset(&block)
end
##
- # Generate an input tag with a type of "text" along with a label tag.
- # This method also has the alias "text" so feel free to use that one
- # instead of input_text.
- #
- # @param [String] label The text to display inside the label tag.
- # @param [String Symbol] name The name of the text field.
- # @param [Hash] args Any additional HTML attributes along with their
- # values.
- # @example
- # form_for(@data, :method => :post) do |f|
- # f.input_text 'Username', :username
- # end
- #
- def input_text(label, name, args = {})
- # The ID can come from 2 places, id_for and the args hash
- id = args[:id] ? args[:id] : id_for(name)
- args = args.merge(:type => :text, :name => name, :id => id)
-
- if !args[:value] and @form_values.respond_to?(name)
- args[:value] = @form_values.send(name)
- end
-
- @g.p do
- label_for(id, label, name)
- @g.input(args)
- end
- end
- alias text input_text
-
- ##
- # Generate an input tag with a type of "password" along with a label.
- # Password fields are pretty much the same as text fields except that
- # the content of these fields is replaced with dots. This method has the
- # following alias: "password".
- #
- # @param [String] label The text to display inside the label tag.
- # @param [String Symbol] name The name of the password field.
- # @param [Hash] args Any additional HTML attributes along with their
- # values.
- # @example
- # form_for(@data, :method => :post) do |f|
- # f.input_password 'My password', :password
- # end
- #
- def input_password(label, name, args = {})
- # The ID can come from 2 places, id_for and the args hash
- id = args[:id] ? args[:id] : id_for(name)
- args = args.merge(:type => :password, :name => name, :id => id)
-
- if !args[:value] and @form_values.respond_to?(name)
- args[:value] = @form_values.send(name)
- end
-
- @g.p do
- label_for(id, label, name)
- @g.input(args)
- end
- end
- alias password input_password
-
- ##
- # Generate a submit tag (without a label). A submit tag is a button that
- # once it's clicked will send the form data to the server.
+ # Generate a button tag (without a label). A button tag is a button that
+ # once it's clicked will call a javascript function.
#
# @param [String] value The text to display in the button.
# @param [Hash] args Any additional HTML attributes along with their
# values.
# @example
# form_for(@data, :method => :post) do |f|
- # f.input_submit 'Save'
+ # f.input_button 'Press', :onclick=>"msg()"
# end
#
- def input_submit(value = nil, args = {})
- args = args.merge(:type => :submit)
- args[:value] = value unless value.nil?
-
- @g.p do
- @g.input(args)
- end
- end
- alias submit input_submit
+ def input_button(value = nil, args = {})
+ args[:value] = value if value
+ tag(:button, nil, args)
+ end # def input_button
+ alias button input_button
##
# Generate an input tag with a type of "checkbox".
@@ -353,112 +368,167 @@ def input_submit(value = nil, args = {})
# to false will hide it.
#
def input_checkbox(label, name, checked = nil, args = {})
- id = args[:id] ? args[:id] : "#{id_for(name)}_0"
-
- # Determine whether or not to show the value of the checkbox
- if args.key?(:show_value)
- show_value = args.delete(:show_value)
- else
- show_value = true
- end
-
- # Determine whether or not to show the label
- if args.key?(:show_label)
- show_label = args.delete(:show_label)
- else
- show_label = true
- end
-
- # Get the checkbox value from either the args hash or from
- # the form object (as specified in the form_for() method).
- if !args[:values] and @form_values.respond_to?(name)
- args[:values] = @form_values.send(name)
- end
-
- # That class for each element wrapper (a span tag) can be customized
- # using :span_class => "a_class".
- if args[:span_class]
- span_class = args[:span_class]
- args.delete(:span_class)
- else
- span_class = "checkbox_wrap"
- end
-
- # Get the type from the args hash instead of pre-defining it. Doing so
- # means we can use this method for the input_radio method.
- args[:type] = :checkbox if !args[:type]
+ opts = {}
+ opts[:label] = label if label
+ opts[:checked] = checked if checked
+ opts[:values] = args.delete(:values) if args.has_key?(:values)
+ opts[:show_value] = args.delete(:show_value) if args.has_key?(:show_value)
+ opts[:show_label] = args.delete(:show_label) if args.has_key?(:show_label)
+ opts[:span_class] = args.delete(:span_class) if args.has_key?(:span_class)
+ type = if args[:type]==:radio then :radio else :checkbox end
+ tag(type, name, args, opts)
+ end
+ alias checkbox input_checkbox
- # Convert the values to an array if it's something we can't use in a loop
- # (e.g. a string).
- if args[:values].class != Hash and args[:values].class != Array
- args[:values] = [args[:values]]
- end
+ ##
+ # Generate an input tag with a type of "color" along with a label tag.
+ # This method also has the alias "color" so feel free to use that one
+ # instead of input_color.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the color field.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_color 'Color', :car_color
+ # end
+ #
+ def input_color(label, name, args = {})
+ tag(:color, name, args, :label=>label)
+ end # def input_color
+ alias color input_color
- # Create a checkbox for each value
- if !args[:values].empty?
- @g.p do
- # Let's create the label and the hidden field
- if show_label === true
- label_for(id, label, name)
- end
+ ##
+ # Generate a select tag with a size=1, along with the option tags
+ # and a label. A size=1 attribute creates a dropdown box; otherwise,
+ # it's the same as a select call.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the select tag.
+ # @param [Hash] args Hash containing additional HTML attributes.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.dropdown 'Country', :country_list
+ # end
+ #
+ def input_dropdown(label, name, args = {})
+ opts = {}
+ opts[:label] = label if label
+ opts[:selected] = args.delete(:selected) if args.has_key?(:selected)
+ opts[:values] = args.delete(:values) if args.has_key?(:values)
+ args[:size] = 1
+ tag(:select, name, args, opts)
+ end
+ alias dropdown input_dropdown
- # Loop through all the values. Each checkbox will have an ID of
- # "form-NAME-INDEX". Each name will be NAME followed by [] to
- # indicate it's an array (since multiple values are possible).
- args[:values].each_with_index do |value, index|
- id = args[:id] ? args[:id] : "#{id_for(name)}_#{index}"
+ ##
+ # Generate a email text box.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the email.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.email 'E-Mail', :email
+ # end
+ #
+ def input_email(label, name, args = {})
+ tag(:email, name, args, :label=>label)
+ end # def email
+ alias email input_email
- if args[:type] == :checkbox
- checkbox_name = "#{name}[]"
- else
- checkbox_name = name
- end
+ ##
+ # Generate a field for uploading files.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the radio tag.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_file 'Image', :image
+ # end
+ #
+ def input_file(label, name, args = {})
+ tag(:file, name, args, :label=>label)
+ end
+ alias file input_file
- # Copy all additional attributes and their values except the
- # values array.
- opts = args.clone
- opts.delete(:values)
+ ##
+ # Generate a hidden field. Hidden fields are essentially the same as
+ # text fields except that they aren't displayed in the browser.
+ #
+ # @param [String Symbol] name The name of the hidden field tag.
+ # @param [String] value The value of the hidden field
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_hidden :user_id
+ # end
+ #
+ def input_hidden(name, value = nil, args = {})
+ args[:value] = value unless value.nil?
+ tag(:hidden, name, args)
+ end
+ alias hidden input_hidden
- # Get the value and text to display for each checkbox
- if value.class == Array
- checkbox_text = value[0]
- checkbox_value = value[1]
- else
- checkbox_text = checkbox_value = value
- end
+ ##
+ # Generate a image tag. An image tag is a submit button that
+ # once it's clicked will send the form data to the server.
+ #
+ # @param [String] value The text to display in the button.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_image 'Save'
+ # end
+ #
+ def input_image(src, args = {})
+ args[:src] = src unless src.nil?
+ tag(:image, nil, args)
+ end
+ alias image input_image
- # Let's see if the current item is checked
- if checked.class == Array
- if checked.include?(checkbox_value)
- opts[:checked] = 'checked'
- end
- else
- if checkbox_value == checked
- opts[:checked] = 'checked'
- end
- end
+ ##
+ # Generate a number in a click box.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the number.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.number 'Age', :age, :min=>1, :max=>120
+ # end
+ #
+ def input_number(label, name, args = {})
+ tag(:number, name, args, :label=>label)
+ end # def number
+ alias number input_number
- # And we're done, easy wasn't it?
- opts = opts.merge(
- :name => checkbox_name, :id => id, :value => checkbox_value
- )
-
- # Generate the following HTML:
- #
- #
- # #{value}
- #
- #
- @g.span(:class => span_class) do
- @g.input(opts)
- " #{checkbox_text}" if show_value === true
- end
- end
- end
- end
+ ##
+ # Generate an input tag with a type of "password" along with a label.
+ # Password fields are pretty much the same as text fields except that
+ # the content of these fields is replaced with dots. This method has the
+ # following alias: "password".
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the password field.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_password 'My password', :password
+ # end
+ #
+ def input_password(label, name, args = {})
+ tag(:password, name, args, :label=>label)
end
- alias checkbox input_checkbox
+ alias password input_password
##
# Generate an input tag with a type of "radio".
@@ -498,63 +568,103 @@ def input_checkbox(label, name, checked = nil, args = {})
def input_radio(label, name, checked = nil, args = {})
# Force a type of "radio"
args[:type] = :radio
-
- if !args[:span_class]
- args[:span_class] = "radio_wrap"
- end
-
+ args[:span_class] = "radio_wrap" unless args[:span_class]
self.input_checkbox(label, name, checked, args)
end
alias radio input_radio
##
- # Generate a field for uploading files.
+ # Generate a range with a slider bar.
#
# @param [String] label The text to display inside the label tag.
- # @param [String Symbol] name The name of the radio tag.
+ # @param [String Symbol] name The name of the range.
# @param [Hash] args Any additional HTML attributes along with their
# values.
# @example
# form_for(@data, :method => :post) do |f|
- # f.input_file 'Image', :image
+ # f.range 'Age', :age, :min=>1, :max=>120
# end
#
- def input_file(label, name, args = {})
- id = args[:id] ? args[:id] : id_for(name)
- args = args.merge(:type => :file, :name => name, :id => id)
+ def input_range(label, name, args = {})
+ tag(:range, name, args, :label=>label)
+ end # def range
+ alias range input_range
- @g.p do
- label_for(id, label, name)
- @g.input(args)
- end
+ ##
+ # Generate a reset tag (without a label). A reset tag is a button that
+ # once it's clicked will reset the form data in the form
+ # back to it's initial state.
+ #
+ # @param [String] value The text to display in the button.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_reset 'Reset! Beware: you will lose the data in your form.'
+ # end
+ #
+ def input_reset(value = nil, args = {})
+ args[:value] = value if value
+ tag(:reset, nil, args)
+ end # def input_reset
+ alias reset input_reset
+
+ ##
+ # Generate a select tag along with the option tags and a label.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the select tag.
+ # @param [Hash] args Hash containing additional HTML attributes.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.select 'Country', :country_list
+ # end
+ #
+ def input_select(label, name, args = {})
+ opts = {}
+ opts[:label] = label if label
+ opts[:selected] = args.delete(:selected) if args.has_key?(:selected)
+ opts[:values] = args.delete(:values) if args.has_key?(:values)
+ tag(:select, name, args, opts)
end
- alias file input_file
+ alias select input_select
##
- # Generate a hidden field. Hidden fields are essentially the same as
- # text fields except that they aren't displayed in the browser.
+ # Generate a submit tag (without a label). A submit tag is a button that
+ # once it's clicked will send the form data to the server.
#
- # @param [String Symbol] name The name of the hidden field tag.
- # @param [String] value The value of the hidden field
+ # @param [String] value The text to display in the button.
# @param [Hash] args Any additional HTML attributes along with their
# values.
# @example
# form_for(@data, :method => :post) do |f|
- # f.input_hidden :user_id
+ # f.input_submit 'Save'
# end
#
- def input_hidden(name, value = nil, args = {})
- args = args.merge(:type => :hidden, :name => name)
-
- if !value and @form_values.respond_to?(name)
- args[:value] = @form_values.send(name)
- else
- args[:value] = value
- end
+ def input_submit(value = nil, args = {})
+ args[:value] = value unless value.nil?
+ tag(:submit, nil, args)
+ end
+ alias submit input_submit
- @g.input(args)
+ ##
+ # Generate an input tag with a type of "text" along with a label tag.
+ # This method also has the alias "text" so feel free to use that one
+ # instead of input_text.
+ #
+ # @param [String] label The text to display inside the label tag.
+ # @param [String Symbol] name The name of the text field.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
+ # @example
+ # form_for(@data, :method => :post) do |f|
+ # f.input_text 'Username', :username
+ # end
+ #
+ def input_text(label, name, args = {})
+ tag(:text, name, args, :label=>label)
end
- alias hidden input_hidden
+ alias text input_text
##
# Generate a text area.
@@ -568,101 +678,261 @@ def input_hidden(name, value = nil, args = {})
# f.textarea 'Description', :description
# end
#
- def textarea(label, name, args = {})
- id = args[:id] ? args[:id] : id_for(name)
-
- # Get the value of the textarea
- if !args[:value] and @form_values.respond_to?(name)
- value = @form_values.send(name)
- else
- value = args[:value]
- args.delete(:value)
- end
+ def input_textarea(label, name, args = {})
+ opts = {}
+ opts[:label] = label if label
+ opts[:value] = args.delete(:value) if args.has_key?(:value)
+ tag(:textarea, name, args, opts)
+ end
+ alias textarea input_textarea
- args = args.merge(:name => name, :id => id)
+ ##
+ # Method used for converting the results of the BlueForm helper to a
+ # string
+ #
+ # @return [String] The form output
+ #
+ def to_s
+ @g.to_s
+ end
- @g.p do
- label_for(id, label, name)
- @g.textarea(args){ value }
- end
+ ##
+ # Method used for converting the results of the BlueForm helper to a
+ # human readable string. This isn't recommended for production because
+ # it requires much more time to generate the HTML output than to_s.
+ #
+ # @return [String] The formatted form output
+ #
+ def to_html
+ @g.to_html
end
##
- # Generate a select tag along with the option tags and a label.
+ # Generate a URL.
#
# @param [String] label The text to display inside the label tag.
- # @param [String Symbol] name The name of the select tag.
- # @param [Hash] args Hash containing additional HTML attributes.
+ # @param [String Symbol] name The name of the url.
+ # @param [Hash] args Any additional HTML attributes along with their
+ # values.
# @example
# form_for(@data, :method => :post) do |f|
- # f.select 'Country', :country_list
+ # f.url 'Description', :description
# end
#
- def select(label, name, args = {})
- id = args[:id] ? args[:id] : id_for(name)
- multiple, size = args.values_at(:multiple, :size)
+ def input_url(label, name, args = {})
+ tag(:url, name, args, :label=>label)
+ end # def url
+ alias url input_url
+
+#-------------------------------------------------------------------------------#
+#--- GENERATE THE HTML HERE ----------------------------------------------------#
+#-------------------------------------------------------------------------------#
+
+ def tag(type, name, args={}, opts={})
+ paragraph_wrapper = if type==:hidden then @hidden_wrapper else @paragraph_wrapper end
+ paragraph_wrapper.call do
+
+ case type
+
+ when :color, :email, :file, :number, :password, :range, :text, :url
+ args[:type] = type
+ args[:name] = name unless args.has_key?(:name) || name.nil?
+ args[:id] = id_for(name) unless args.has_key?(:id) || name.nil?
+ value = extract_values_from_object(name, args) unless args.has_key?(:value)
+ args[:value] = value if value
+ error = if name then @form_errors.delete(name.to_s) else nil end
+
+ @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label)
+ @input_wrapper.call do
+ if opts.has_key?(:span_class)
+ @g.span(accept(opts, [:span_class])) do
+ @g.input(args)
+ end
+ else
+ @g.input(args)
+ end
+ end
+ @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error
- # Get all the values
- if !args[:values] and @form_values.respond_to?(name)
- values = @form_values.send(name)
- else
- values = args[:values]
- args.delete(:values)
- end
+ when :button, :image, :reset, :submit
+ args[:type] = type
+ args[:name] = name unless args.has_key?(:name) || name.nil?
+ @input_wrapper.call do
+ @g.input(args)
+ end
- args[:multiple] = 'multiple' if multiple
- args[:size] = (size || values.count || 1).to_i
- args[:name] = multiple ? "#{name}[]" : name
- args = args.merge(:id => id)
-
- # Retrieve the selected value
- has_selected, selected = args.key?(:selected), args[:selected]
- selected = [selected] if !selected.is_a?(Array)
- args.delete(:selected)
-
- @g.p do
- label_for(id, label, name)
- @g.select args do
- values.each do |value, o_name|
- o_name ||= value
- o_args = {:value => value}
-
- if has_selected and selected.include?(value)
- o_args[:selected] = 'selected'
+ when :textarea
+ args[:name] = name unless args.has_key?(:name) || name.nil?
+ args[:id] = id_for(name) unless args.has_key?(:id)
+ value = extract_values_from_object(name, args) unless opts.has_key?(:value)
+ opts[:value] = value if value
+ error = if name then @form_errors.delete(name.to_s) else nil end
+
+ @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label)
+ @input_wrapper.call do
+ if opts.has_key?(:span_class)
+ @g.span(accept(opts, [:span_class])) do
+ @g.textarea(args) {opts[:value]}
+ end
+ else
+ @g.textarea(args) {opts[:value]}
end
-
- @g.option(o_args){ o_name }
end
- end
- end
- end
+ @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error
+
+ when :hidden
+ args[:type] = type
+ args[:name] = name unless args.has_key?(:name) || name.nil?
+ args[:value] = extract_values_from_object(name, args) unless args.has_key?(:value)
+ @g.input(args)
+
+ when :checkbox, :radio
+ args[:type] = type
+ args[:name] = nil
+ args[:id] = "#{id_for(name)}_0" unless args.has_key?(:id)
+ error = if name then @form_errors.delete(name.to_s) else nil end
+
+ # Get the options or their defaults
+ span_class = if opts.has_key?(:span_class) then opts[:span_class] else "checkbox_wrap" end
+ show_label = if opts.has_key?(:show_label) then opts[:show_label] else true end
+ show_value = if opts.has_key?(:show_value) then opts[:show_value] else true end
+
+ # Get all the values or checked from the form object
+ has_values = opts.has_key?(:values)
+ has_checked = opts[:checked]
+ if has_values
+ values = opts[:values]
+ if has_checked
+ checked = opts[:checked]
+ else
+ checked = extract_values_from_object(name, args)
+ end
+ else
+ values = extract_values_from_object(name, args)
+ values = [] if values.nil?
+ if has_checked
+ checked = opts[:checked]
+ else
+ checked = []
+ end
+ end
+ values = [values] unless [Array,Hash].index(values.class)
+ checked = [checked] unless [Array,Hash].index(checked.class)
- ##
- # Method used for converting the results of the BlueForm helper to a
- # string
- #
- # @return [String] The form output
- #
- def to_s
- @g.to_s
- end
+ # Loop through all the values. Each checkbox will have an ID of
+ # "form-NAME-INDEX". Each name will be NAME followed by [] to
+ # indicate it's an array (since multiple values are possible).
+ @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label) && show_label
+ @input_wrapper.call do
+ values.each_with_index do |value,index|
+ args[:id] = "#{id_for(name)}_#{index}"
+
+ # The id is an array for checkboxes, and elemental for radio buttons
+ checkbox_name = if type == :checkbox then "#{name}[]" else name end
+ args[:name] = checkbox_name
+
+ # Get the value and text to display for each checkbox
+ if value.class == Array
+ # It's a hash in inverted ([value,key]) order
+ checkbox_text = value[0]
+ checkbox_value = value[1]
+ else
+ # It's one value of an array
+ checkbox_text = checkbox_value = value
+ end
+ args[:value] = checkbox_value
+
+ # Let's see if the current item is checked
+ if checked.include?(checkbox_value)
+ args[:checked] = 'checked'
+ else
+ args.delete(:checked)
+ end
+
+ @g.span(:class=>span_class) do
+ @g.input(args)
+ " #{checkbox_text}" if show_value == true
+ end
+ end
+ end # @input_wrapper
+ @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error
+
+ when :select
+ id = args[:id] ? args[:id] : id_for(name)
+ multiple, size = args.values_at(:multiple, :size)
+ error = if name then @form_errors.delete(name.to_s) else nil end
+
+ # Get all the values or selected from the form object
+ has_values = opts.has_key?(:values)
+ has_selected = opts[:selected]
+ if has_values
+ values = opts[:values]
+ if has_selected
+ selected = opts[:selected]
+ else
+ selected = extract_values_from_object(name, args)
+ end
+ else
+ values = extract_values_from_object(name, args)
+ values = [] if values.nil?
+ if has_selected
+ selected = opts[:selected]
+ else
+ selected = []
+ end
+ end
+ values = [values] unless [Array,Hash].index(values.class)
+ selected = [selected] unless [Array,Hash].index(selected.class)
+
+ args[:multiple] = 'multiple' if multiple
+ args[:size] = (size || values.count || 1).to_i
+ args[:name] = multiple ? "#{name}[]" : name
+ args = args.merge(:id => id)
+
+ @label_wrapper.call { @g.label(opts[:label], :for => args[:id]) } if opts.has_key?(:label)
+ @input_wrapper.call do
+ @g.select(args) do
+ values.each do |value, option_name|
+ option_name ||= value
+ option_args = {:value => value}
+ option_args[:selected] = 'selected' if selected.include?(value)
+ @g.option(option_args){ option_name }
+ end # opts[:values].each
+ end # @g.select
+ end # @input_wrapper.call
+ @label_wrapper.call { @g.span(:class=>"error") { " #{error}" } } if error
+
+ else
+ raise ArgumentError.new("Blueform doesn't support HTML5 type '#{type}'")
+ end # case
+
+ end # paragraph_wrapper.call
+ end # tag
private
##
- # Generate a label based on the id and value.
- #
- # @param [String] id The ID to which the label belongs.
- # @param [String] value The text to display inside the label tag.
- # @param [String] name The name of the field to which the label belongs.
+ # If possible, extract the data from the form object.
#
- def label_for(id, value, name)
- if error = @form_errors.delete(name.to_s)
- @g.label("#{value} ", :for => id){ @g.span(:class => :error){ error } }
- else
- @g.label(value, :for => id)
+ # @param [String] field_name The name of the field.
+ # @return [Array] The args parameter. Extract looks
+ # for the :value=>:name parameter in order to
+ # extract data from the form object.
+ #
+ def extract_values_from_object(name, args)
+ # If conditions are right, get the value from the input object.
+ case
+ when name.nil?
+ # This control doesn't use value look up
+ when args.has_key?(:value)
+ # Don't override given value.
+ when @form_object.nil?
+ # No structure to look up a value.
+ when @form_object.respond_to?(name)
+ # There's a data element, so get the value.
+ @form_object.send(name)
end
- end
+ end # extract_values_from_object
##
# Generate a value for an ID tag based on the field's name.
@@ -671,12 +941,21 @@ def label_for(id, value, name)
# @return [String] The ID for the specified field name.
#
def id_for(field_name)
+ raise ArgumentError.new("No field name passed to id_for") if field_name.nil?
if name = @form_args[:name]
"#{name}_#{field_name}".downcase.gsub(/-/, '_')
else
"form_#{field_name}".downcase.gsub(/-/, '_')
end
- end
+ end # id_for
+
+ ##
+ # Create a new hash with only the elements which have listed keys
+ #
+ def accept(hash, keys=[])
+ hash.select { |k,v| keys.index(k) }
+ end # accept
+
end # Form
end # BlueForm
end # Helper
diff --git a/lib/ramaze/scaffolding.rb b/lib/ramaze/scaffolding.rb
new file mode 100644
index 00000000..9cd56ca9
--- /dev/null
+++ b/lib/ramaze/scaffolding.rb
@@ -0,0 +1,428 @@
+require "ramaze/gestalt"
+
+module Ramaze
+ ##
+ # The scaffolding class is a generator that builds a simple CRUD controller for any database table.
+ # This capability is meant only for development, as the resulting controllers have NO SECURITY
+ # code built into them. These controllers make it easy to manipulate the database tables during
+ # development.
+ #
+ # The controllers are encapsulated in ... tags so that you can write
+ # CSS statements that will only apply to scaffolding.
+ #
+ # The way it works is that it reads the database table to get the list of fields in the table.
+ # Next, it takes a prewritten CRUD controller and tailors it based on the fields in the table.
+ # It's more complicated to do than than it seems, but the output of this generator is the
+ # controller in the form of a String object.
+ #
+ # The common way to use it is to call it to create the controller, the use class_eval to install it
+ # on the fly. You can do this in your 'controller/init.rb' module if you want it to be permanent,
+ # but be sure you only generate the controllers in 'dev' mode because, again, they have NO SECURITY
+ # built into them.
+ #
+ # These controllers are created once during load time, so the cost of using them is negligible
+ # while Ramaze is running. All the configuring is done at load time, so the generated code does
+ # not need to look at the table's schema to operate.
+ #
+ # If these controllers are in your production version, any idiot hacker can use them to examine
+ # and modify your database. So let me repeat:
+ #
+ # THESE CONTROLLERS ARE FOR DEVELOPMENT USE ONLY.
+ #
+ # The test table is:
+ # DB::drop_table?(:coltypes)
+ # DB::create_table(:coltypes) do # common database type used
+ # primary_key :id # int(11) + primary key
+ # Integer :int11 # int(11)
+ # String :vc255 # varchar(255)
+ # String :vc50, :size=>50 # varchar(50)
+ # String :c255, :fixed=>true # char(255)
+ # String :c50, :fixed=>true, :size=>50 # char(50)
+ # String :text, :text=>true # text
+ # File :blob # blob
+ # Fixnum :fixnum # int(11)
+ # Bignum :bignum # bigint(20)
+ # Float :dblflt # double
+ # BigDecimal :bigdec # decimal(10,0)
+ # BigDecimal :big6dec, :size=>6 # decimal(6,0)
+ # BigDecimal :big10dec2, :size=>[10, 2] # decimal(10,2)
+ # Date :justdate # date
+ # DateTime :datetime # datetime
+ # Time :justtime # datetime
+ # Time :timeonly, :only_time=>true # time
+ # Numeric :numeric # decimal(10,0)
+ # TrueClass :booltrue # tinyint(1)
+ # FalseClass :boolfalse # tinyint(1)
+ # DateTime :created_at # datetime
+ # DateTime :updated_at # datetime
+ # end
+ #
+ class Scaffolding
+
+ Sequel.extension :inflector # http://sequel.jeremyevans.net/rdoc-plugins/classes/String.html
+
+ ##
+ # This is the core CRUD controller. It has no comments for efficiency. There's no magic
+ # here: it's just simple Ruby/Sequel programming.
+ def initialize
+ @prototype = [
+ "class NilClass", :eol,
+ " def strftime(pattern)", :eol,
+ " \"\"", :eol,
+ " end", :eol,
+ "end", :eol,
+ :eol,
+ "class ", :model_string_singular_camel, "Controller < Controller", :eol,
+ :eol,
+ " map '/", :model_string_singular, "'", :eol,
+ :eol,
+ " def initialize", :eol,
+ " @columns = ", :columns_list, :eol,
+ " @index_columns = ", :index_columns_list, :eol,
+ " @new_columns = ", :new_columns_list, :eol,
+ " @show_columns = ", :show_columns_list, :eol,
+ " @edit_columns = ", :edit_columns_list, :eol,
+ " end", :eol,
+ :eol,
+ " def index", :eol,
+ " @g = Ramaze::Gestalt.new", :eol,
+ " @title = \"List of ", :model_string_plural_camel, "\"", :eol,
+ " @g.scaffolding do", :eol,
+ " rows = ", :model_string_singular_camel, ".select(*@index_columns).all", :eol,
+ " @g.h3 { @title }", :eol,
+ " @g.p do", :eol,
+ " @g.a(:href=>\"/", :model_string_singular, "/new\") { \"new\" }", :eol,
+ " end", :eol,
+ " @g.table do", :eol,
+ " # create the heading", :eol,
+ " @g.tr do", :eol,
+ " @index_columns.each do |col|", :eol,
+ " @g.td do", :eol,
+ " @g.strong { col.to_s.titleize }", :eol,
+ " end", :eol,
+ " end", :eol,
+ " end", :eol,
+ " # list all the rows", :eol,
+ " rows.each do |row|", :eol,
+ " @g.tr do", :eol,
+ " row.each do |col,value|", :eol,
+ " @g.td { value.to_s }", :eol,
+ " end", :eol,
+ " @g.td do", :eol,
+ " @g.a(:href=>\"/", :model_string_singular, "/show?id=%s\"%row[:id]) { \"show\" }", :eol,
+ " @g << \" | \"", :eol,
+ " @g.a(:href=>\"/", :model_string_singular, "/edit?id=%s\"%row[:id]) { \"edit\" }", :eol,
+ " @g << \" | \"", :eol,
+ " @g.a(:href=>\"/", :model_string_singular, "/show?id=%s&delete\"%row[:id]) { \"delete\" }", :eol,
+ " end", :eol,
+ " end", :eol,
+ " end", :eol,
+ " end", :eol,
+ " end", :eol,
+ " @g.to_s", :eol,
+ " end", :eol,
+ :eol,
+ " def new", :eol,
+ " @g = Ramaze::Gestalt.new", :eol,
+ " @title = \"New ", :model_string_singular_camel, "\"", :eol,
+ " @g.scaffolding do", :eol,
+ " @g.h3 { @title }", :eol,
+ " row = ", :model_string_singular_camel, ".new", :eol,
+ " @g.form(:method=>:post, :action=>:save_new) do", :eol,
+ " @g.table do", :eol,
+ :new_columns,
+ " end", :eol,
+ " @g.br", :eol,
+ " @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Back\")", :eol,
+ " @g << \" \"", :eol,
+ " @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Save\")", :eol,
+ " end", :eol,
+ " end", :eol,
+ " @g.to_s", :eol,
+ " end", :eol,
+ :eol,
+ " def show", :eol,
+ " @g = Ramaze::Gestalt.new", :eol,
+ " @title = \"Show ", :model_string_singular_camel, "\"", :eol,
+ " @g.scaffolding do", :eol,
+ " @g.h3 { @title }", :eol,
+ " row = ", :model_string_singular_camel, ".where(:id=>session.request.params['id']).first", :eol,
+ " @g.form(:method=>:post, :action=>:save_show) do", :eol,
+ " @g.input(:type=>:hidden, :name=>:id, :value=>row.id)", :eol,
+ " @g.table do", :eol,
+ :show_columns,
+ " end", :eol,
+ " @g.br", :eol,
+ " @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Back\")", :eol,
+ " if session.request.params.has_key?('delete')", :eol,
+ " @g << \" \"", :eol,
+ " @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Delete\")", :eol,
+ " end", :eol,
+ " end", :eol,
+ " end", :eol,
+ " @g.to_s", :eol,
+ " end", :eol,
+ :eol,
+ " def edit", :eol,
+ " @g = Ramaze::Gestalt.new", :eol,
+ " @title = \"Edit ", :model_string_singular_camel, "\"", :eol,
+ " @g.scaffolding do", :eol,
+ " @g.h3 { @title }", :eol,
+ " row = ", :model_string_singular_camel, ".where(:id=>session.request.params['id']).first", :eol,
+ " row.updated_at = Time.now", :eol,
+ " @g.form(:method=>:post, :action=>:save_edit) do", :eol,
+ " @g.input(:type=>:hidden, :name=>:id, :value=>row.id)", :eol,
+ " @g.table do", :eol,
+ :edit_columns,
+ " end", :eol,
+ " @g.br", :eol,
+ " @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Back\")", :eol,
+ " @g << \" \"", :eol,
+ " @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Save\")", :eol,
+ " end", :eol,
+ " end", :eol,
+ " @g.to_s", :eol,
+ " end", :eol,
+ :eol,
+ " def save_new", :eol,
+ " if session.request.params['goto']==\"Save\"", :eol,
+ " row = ", :model_string_singular_camel, ".new", :eol,
+ " row.set_fields(session.request.params, @new_columns, :missing=>:skip)", :eol,
+ " row.id = nil", :eol,
+ " row.created_at = Time.now if @columns.index(:created_at)", :eol,
+ " row.updated_at = Time.now if @columns.index(:updated_at)", :eol,
+ " row.save", :eol,
+ " end", :eol,
+ " redirect(\"/", :model_string_singular, "/index\")", :eol,
+ " end", :eol,
+ :eol,
+ " def save_show", :eol,
+ " if session.request.params['goto']==\"Delete\"", :eol,
+ " row = ", :model_string_singular_camel, ".where(:id=>session.request.params['id']).first", :eol,
+ " row.delete", :eol,
+ " end", :eol,
+ " redirect(\"/", :model_string_singular, "/index\")", :eol,
+ " end", :eol,
+ :eol,
+ " def save_edit", :eol,
+ " if session.request.params['goto']==\"Save\"", :eol,
+ " row = ", :model_string_singular_camel, ".where(:id=>session.request.params['id']).first", :eol,
+ " row.set_fields(session.request.params, @edit_columns, :missing=>:skip)", :eol,
+ " row.updated_at = Time.now if @columns.index(:updated_at)", :eol,
+ " row.save", :eol,
+ " redirect(\"/", :model_string_singular, "/index\")", :eol,
+ " end", :eol,
+ " redirect(\"/", :model_string_singular, "/index\")", :eol,
+ " end", :eol,
+ :eol,
+ "end", :eol ]
+ end
+
+ ##
+ # This method builds the controller.
+ #
+ # @param Hash args A has containing the options.
+ #
+ # @param HashElement :model The name of the database table for
+ # which the controller will be built. This name must be lower
+ # case singular symbol and there must be a table in the database
+ # which has this name as lower case plural.
+ #
+ # @example A table named 'coltypes'. The table must exist in the DB.
+ #
+ # :model => :coltype
+ #
+ # @param HashElement :index_columns => [ ... ] A list of the
+ # columns to display in the 'index' method as a list of Symbols.
+ # Since fields are listed horizontally, be careful not to list
+ # too many.
+ #
+ # @example A list of fields.
+ #
+ # :index_columns=>[:id, :vc255, :int11]
+ #
+ # @param HashElement :new_columns => [ ... ] A list of the columns
+ # to be displayed on the 'new' page. DON'T include the table's
+ # primary key in this list. Usually you would not include :created_at
+ # or :updated_at, if the table has those fields. The controller
+ # updates those automatically.
+ #
+ # @param HashElement :show_columns => [ ... ] A list of columns
+ # to be displayed on the 'show' page. Just omit this option to
+ # show all the fields (recommended).
+ #
+ # @option HashElement :edit_columns => [ ... ] A list of columns
+ # to permit editing on the 'edit' page. DON'T include the table's
+ # primary key in this list. Usually you would not include :created_at
+ # or :updated_at, if the table has those fields. The controller
+ # updates those automatically.
+ #
+ # BUILDING A CONTROLLER
+ # If you do not have a Sequel::Model for the table, create an empty one.
+ #
+ # @example Create an empty 'coltypes' table model.
+ #
+ # class Coltype < Sequel::Model
+ # end
+ #
+ # Call the build routine, and direct the output to 'class_eval'.
+ #
+ # In 'controller/init.rb' (just a suggestion), add this code:
+ #
+ # Object::class_eval(Scaffolding.new.build_controller(
+ # :model=>:coltype,
+ # :index_columns=>[:id, :vc255, :int11],
+ # :new_columns=>[:id, :vc255, :int11],
+ # :show_columns=>[:id, :vc255, :int11],
+ # :edit_columns=>[:id, :vc255, :int11]
+ # ))
+ #
+ def build_controller(args)
+ # Prepare the substitution parameters
+ @constant = constant = {}
+
+ constant[:model_symbol_singular] = args[:model]
+ constant[:model_string_singular] = args[:model].to_s
+ constant[:model_string_plural] = args[:model].to_s.pluralize
+ constant[:model_string_plural_camel] = constant[:model_string_singular].pluralize.camelize
+ constant[:model_string_singular_camel] = constant[:model_string_singular].camelize
+
+ @schema = DB.schema(constant[:model_string_plural]).to_h
+ @columns = @schema.keys
+ @index_columns = if args.has_key?(:index_columns) then args[:index_columns] else @columns end
+ @new_columns = if args.has_key?(:new_columns) then args[:new_columns] else @columns end
+ @show_columns = if args.has_key?(:show_columns) then args[:show_columns] else @columns end
+ @edit_columns = if args.has_key?(:edit_columns) then args[:edit_columns] else @columns end
+
+ @schema.each do |name,properties|
+ # see if it has something like decimal[10,2], decimal[2], or just decimal
+ db_type = properties[:db_type]
+ case
+ when m = db_type.match(/^([a-z]*)\(([0-9]*),([0-9]*)\)$/)
+ a = m[2].to_i
+ b = m[3].to_i
+ when m = db_type.match(/^([a-z]*)\(([0-9]*)\)$/)
+ a = m[2].to_i
+ b = 0
+ else
+ a = 0
+ b = 0
+ end
+
+ case properties[:type]
+ when :integer
+ a = 11 if a==0
+ width = a
+ boxtype = :number
+ when :string
+ a = 32 if a==0 || a>80
+ width = a
+ boxtype = if properties[:db_type]=='text' then :textarea else :text end
+ when :blob
+ width = 80
+ boxtype = :textarea
+ when :float
+ a = 16 if a==0
+ width = a
+ boxtype = :text
+ when :decimal
+ a = 12 if a==0
+ width = a
+ boxtype = :text
+ when :date
+ width = 10
+ boxtype = :date
+ when :datetime
+ width = 17
+ boxtype = :datetime
+ when :time
+ width = 8
+ boxtype = :time
+ when :boolean
+ width = 0
+ boxtype = :checkbox
+ end
+
+ properties[:width] = width
+ properties[:boxtype] = boxtype
+ end
+
+ @source = []
+ source(@prototype)
+ @source.join
+ end
+
+private
+
+ # As the prototype code above is passed to this method, it copies Strings to the
+ # output, and processes the Symbols as appropriate. It cannot be called by the user.
+ def source(objs)
+ objs.each do |obj|
+ case
+ when obj==:new_columns
+ @new_columns.each do |col|
+ field(:new, col, @schema[col])
+ end
+ when obj==:show_columns
+ @show_columns.each do |col|
+ field(:show, col, @schema[col])
+ end
+ when obj==:edit_columns
+ @edit_columns.each do |col|
+ field(:edit, col, @schema[col])
+ end
+ when obj==:columns_list
+ @source << @columns.inspect
+ when obj==:index_columns_list
+ @source << @index_columns.inspect
+ when obj==:new_columns_list
+ @source << @new_columns.inspect
+ when obj==:show_columns_list
+ @source << @show_columns.inspect
+ when obj==:edit_columns_list
+ @source << @edit_columns.inspect
+ when obj==:eol
+ @source << "\n"
+ when obj.class==String
+ @source << obj
+ when obj.class==Symbol
+ @source << @constant[obj]
+ end
+ end
+ end
+
+ ##
+ # This method is used by 'build_controller' to generate each set of
+ # code for each field specified. It cannot be called by the user.
+ def field(type, col, properties)
+ disabled = if type==:show then ", :disabled=>true" else "" end
+ source([" @g.tr do", :eol])
+ source([" @g.td { @g.strong { \"#{col.to_s.humanize}\" } }", :eol])
+ source([" @g.td do", :eol])
+ case properties[:boxtype]
+ when :checkbox
+ source([
+ " @g.input(:type=>:hidden, :name=>#{col.inspect}, :id=>\"form_#{col.to_s}\", :value=>0)", :eol,
+ " opts = {:type=>:checkbox, :name=>#{col.inspect}, :id=>\"form_#{col.to_s}\", :value=>1#{disabled}}", :eol,
+ " opts[:checked] = true if row[#{col.inspect}]", :eol,
+ " @g.input(opts)", :eol ])
+ when :number
+ source([" opts = @g.input(:type=>:number, :name=>#{col.inspect}, :value=>row[#{col.inspect}], :size=>#{properties[:width]}, :id=>\"form_#{col}\"#{disabled})", :eol])
+ when :text
+ source([" @g.input(:type=>:text, :name=>#{col.inspect}, :value=>row[#{col.inspect}], :size=>#{properties[:width]}, :id=>\"form_#{col}\"#{disabled})", :eol])
+ when :date
+ source([" @g.input(:type=>:text, :name=>#{col.inspect}, :value=>row[#{col.inspect}].strftime(\"%Y-%m-%d\"), :size=>#{properties[:width]}, :id=>\"form_#{col}\"#{disabled})", :eol])
+ when :datetime
+ source([" @g.input(:type=>:text, :name=>#{col.inspect}, :value=>row[#{col.inspect}].strftime(\"%Y-%m-%d %H:%M:%S\"), :size=>#{properties[:width]}, :id=>\"form_#{col}\"#{disabled})", :eol])
+ when :time
+ source([" @g.input(:type=>:text, :name=>#{col.inspect}, :value=>row[#{col.inspect}].strftime(\"%H:%M:%S\"), :size=>#{properties[:width]}, :id=>\"form_#{col}\"#{disabled})", :eol])
+ when :textarea
+ source([" @g.textarea(:name=>#{col.inspect}, :rows=>5, :cols=>#{properties[:width]}, :id=>\"form_#{col}\"#{disabled}) { row[#{col.inspect}] }", :eol])
+ end
+ source([" end", :eol])
+ source([" end", :eol])
+ end
+
+ end
+
+end
diff --git a/spec/ramaze/helper/blue_form.rb b/spec/ramaze/helper/blue_form.rb
index 6f50d39d..63fb1a56 100644
--- a/spec/ramaze/helper/blue_form.rb
+++ b/spec/ramaze/helper/blue_form.rb
@@ -1,16 +1,18 @@
require File.expand_path('../../../../spec/helper', __FILE__)
require 'ramaze/helper/blue_form'
-describe BF = Ramaze::Helper::BlueForm do
+describe BF = Ramaze::Helper::BlueForm do # original tests
extend BF
# Generate some dummy data
@data = Class.new do
+ attr_accessor :person
attr_reader :username
attr_reader :password
attr_reader :assigned
attr_reader :assigned_hash
attr_reader :message
+ attr_accessor :server
attr_reader :servers_hash
attr_reader :servers_array
attr_accessor :errors
@@ -30,67 +32,981 @@ def initialize
end
end.new
+ class BlueFormModel
+ attr_accessor :errors
+ def set_fields(hash, fields, opts={})
+ @errors = {}
+ fields.each do |f|
+ if hash.has_key?(f)
+ instance_variable_set("@#{f}", hash[f])
+ elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
+ instance_variable_set("@#{sf}", hash[sf])
+ else
+ raise NoMethodError.new("undefined method `#{f.to_s}=' for #{self.inspect}") \
+ if opts[:missing]!=:skip
+ end
+ end
+ self
+ end
+ end
+
+ class UserX < BlueFormModel
+ attr_accessor :username, :password, :gender, :country, :errors
+ def initialize
+ @errors={}
+ end
+ end
+
# very strange comparision, sort all characters and compare, so we don't have
# order issues.
def assert(expected, output)
left = expected.to_s.gsub(/\s+/, ' ').gsub(/>\s+, '><').strip
right = output.to_s.gsub(/\s+/, ' ').gsub(/>\s+, '><').strip
- left.scan(/./).sort.should == right.scan(/./).sort
+ lsort = left.scan(/./).sort
+ rsort = right.scan(/./).sort
+ lsort.should == rsort
+ end
+
+ # ------------------------------------------------
+ # Basic forms
+ it 'Make a basic form' do
+ out = form_for(@data, :method => :post)
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it 'Make a form with the method and action attributes specified' do
+ out = form_for(@data, :method => :post, :action => '/')
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it 'Make a form with a method, action and a name attribute' do
+ out = form_for(@data, :method => :post, :action => '/', :name => :spec)
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it 'Make a form with a class and an ID' do
+ out = form_for(@data, :class => :foo, :id => :bar)
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it 'Make a form with a fieldset and a legend' do
+ out = form_for(@data, :method => :get) do |f|
+ f.fieldset do
+ f.legend('The Form')
+ end
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ #
+ # ------------------------------------------------
+ # tag forms
+ it '1. Make a :text form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:text, :username, {}, {:label=>"Username"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '2. Make a :text form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:text, :username, {:value=>"mrboo"}, {:label=>"Username"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '3. Make a :text form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:text, :username, {:size=>10, :id=>"my_id"}, {:label=>"Username"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '4. Make a :password form with name and opts' do
+ out = form_for(nil, :method => :get) do |f|
+ f.tag(:password, :password, {}, {:label=>"Password"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '5. Make a :password form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:password, :password, {:value=>"super-secret-password", :class=>"password_class"}, {:label=>"Password"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '6. Make a :submit form' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:submit, nil, {}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '7. Make a :submit form with args' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:submit, nil, {:value=>"Send"}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '8. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '9. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>"bacon"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '10. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>"boo", :values=>["boo"]})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '11. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>["boo"], :values=>["boo", "foo"]})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '12. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :checked=>["boo"], :values=>{"Boo"=>"boo"}})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '13. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :show_value=>false})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '14. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned, {}, {:label=>"Assigned", :show_label=>false})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '15. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned_hash, {}, {:label=>"Assigned"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '16. Make a :checkbox form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:checkbox, :assigned_hash, {}, {:label=>"Assigned", :checked=>"bacon"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '17. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '18. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :checked=>"bacon", :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '19. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :checked=>"boo", :values=>["boo"], :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '20. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :show_value=>false, :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '21. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned, {:type=>:radio}, {:label=>"Assigned", :show_label=>false, :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '22. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned_hash, {:type=>:radio}, {:label=>"Assigned", :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '23. Make a :radio form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:radio, :assigned_hash, {:type=>:radio}, {:label=>"Assigned", :checked=>"bacon", :span_class=>"radio_wrap"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '24. Make a :file form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:file, :file, {}, {:label=>"File"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '24. Make a :file form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:file, :file, {:id=>"awesome_file"}, {:label=>"File"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '25. Make a :hidden form with name' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:hidden, :username, {}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '26. Make a :hidden form with name and args' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:hidden, :username, {:value=>"Bob Ross"}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '27. Make a :hidden form with name and args' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:hidden, :username, {:id=>"test", :value=>"Bob Ross"}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '28. Make a :textarea form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:textarea, :message, {}, {:label=>"Message"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '29. Make a :textarea form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:textarea, :message, {}, {:label=>"Message", :value=>"stuff"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '30. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_hash, {}, {:label=>"Server"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '31. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_hash, {}, {:label=>"Server", :selected=>:mongrel})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '32. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_array, {}, {:label=>"Server"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '33. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_array, {}, {:label=>"Server", :selected=>"Mongrel"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '34. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :people_hash, {}, {:label=>"People", :values=>{:chuck=>"Chuck", :bob=>"Bob"}})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '35. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :people_hash, {}, {:label=>"People", :selected=>:chuck, :values=>{:chuck=>"Chuck", :bob=>"Bob"}})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '36. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :people_array, {}, {:label=>"People", :values=>["Chuck", "Bob"]})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '37. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :people_array, {}, {:label=>"People", :selected=>"Chuck", :values=>["Chuck", "Bob"]})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '38. Make a :select form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_hash, {:multiple=>:multiple}, {:label=>"Server"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '39. Make a :select form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_hash, {:multiple=>:multiple}, {:label=>"Server", :selected=>:webrick})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '40. Make a :select form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :servers_hash, {:multiple=>:multiple}, {:label=>"Server", :selected=>[:webrick, :mongrel]})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '41. Make a :button form with args' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:button, nil, {:onclick=>"fcn()", :value=>"Accept"}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '42. Make a :color form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:color, :my_color, {}, {:label=>"Choose a color"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '43. Make a :email form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:email, :email, {}, {:label=>"Email"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '44. Make a :image form with args' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:image, nil, {:alt=>"Submit", :src=>"http://www.w3schools.com/tags/img_submit.gif"}, {})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '45. Make a :number form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:number, :age, {:min=>1, :max=>120}, {:label=>"Age"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '46. Make a :range form with name, args, and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:range, :cost, {:min=>0, :max=>100}, {:label=>"Cost"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
end
- # ------------------------------------------------
- # Basic forms
+ it '47. Make a :reset form' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:reset, nil, {}, {})
+ end
- it 'Make a basic form' do
- out = form_for(@data, :method => :post)
assert(<<-FORM, out)
-
+
FORM
end
- it 'Make a form with the method and action attributes specified' do
- out = form_for(@data, :method => :post, :action => '/')
+ it '48. Make a :reset form with args' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:reset, nil, {:value=>"Reset"}, {})
+ end
+
assert(<<-FORM, out)
-
+
FORM
end
- it 'Make a form with a method, action and a name attribute' do
- out = form_for(@data, :method => :post, :action => '/', :name => :spec)
+ it '49. Make a :url form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:url, :url, {}, {:label=>"URL"})
+ end
+
assert(<<-FORM, out)
-
+
FORM
end
- it 'Make a form with a class and an ID' do
- out = form_for(@data, :class => :foo, :id => :bar)
+ it '50. Make a :select form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:select, :person, {}, {:label=>"Person", :selected=>"chuck", :values=>{"chuck"=>"Chuck", "bob"=>"Bob"}})
+ end
+
assert(<<-FORM, out)
-
+
FORM
end
- it 'Make a form with a fieldset and a legend' do
+ it '51. Make a :select form with name and opts' do
out = form_for(@data, :method => :get) do |f|
- f.fieldset do
- f.legend('The Form')
- end
+ f.tag(:select, :person, {}, {:label=>"Person", :selected=>"chuck",:values=>{"chuck"=>"Chuck", "bob"=>"Bob"}})
end
assert(<<-FORM, out)
+ FORM
+ end
+
+ it '60. Make a :text/:password form with name and opts' do
+ params = {:username=>"gladys", :password=>"abc", :gender=>"F", :country=>"SV"}
+ user = UserX.new
+ user.set_fields(params, [:username, :password, :gender, :country], :missing=>:skip)
+ user.errors[:username] = "User not in system"
+ user.errors[:password] = "The username/password combination is not on our system"
+ out = form_for(user, :method => :post, :action=>"login2") do |f|
+ f.tag(:text, :username, {}, {:label=>"Username: "})
+ f.tag(:password, :password, {}, {:label=>"Password: "})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '98. Make a :text form with name and opts' do
+ form_error :username, 'May not be empty'
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:text, :username, {}, {:label=>"Username"})
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '99. Make a :text form with name and opts' do
+ out = form_for(@data, :method => :get) do |f|
+ f.tag(:text, :username, {}, {:label=>"Username"})
+ end
+
+ assert(<<-FORM, out)
+
FORM
end
+
+ # ------------------------------------------------
+ # Clear out previous simulated errors
+ @form_errors = {}
+
# ------------------------------------------------
# Text fields
- it 'Make a form with input_text(label, value)' do
+ it '101. Make a form with input_text(label, value)' do
out = form_for(@data, :method => :get) do |f|
f.input_text 'Username', :username
end
@@ -105,7 +1021,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_text(username, label, value)' do
+ it '102. Make a form with input_text(username, label, value)' do
out = form_for(@data, :method => :get) do |f|
f.input_text 'Username', :username, :value => 'mrboo'
end
@@ -120,7 +1036,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_text(label, name, size, id)' do
+ it '103. Make a form with input_text(label, name, size, id)' do
out = form_for(@data, :method => :get) do |f|
f.input_text 'Username', :username, :size => 10, :id => 'my_id'
end
@@ -138,7 +1054,7 @@ def assert(expected, output)
# ------------------------------------------------
# Password fields
- it 'Make a form with input_password(label, name)' do
+ it '104. Make a form with input_password(label, name)' do
out = form_for(nil , :method => :get) do |f|
f.input_password 'Password', :password
end
@@ -153,7 +1069,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_password(label, name, value, class)' do
+ it '105. Make a form with input_password(label, name, value, class)' do
out = form_for(@data, :method => :get) do |f|
f.input_password 'Password', :password, :value => 'super-secret-password', :class => 'password_class'
end
@@ -171,7 +1087,7 @@ def assert(expected, output)
# ------------------------------------------------
# Submit buttons
- it 'Make a form with input_submit()' do
+ it '106. Make a form with input_submit()' do
out = form_for(@data, :method => :get) do |f|
f.input_submit
end
@@ -185,7 +1101,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_submit(value)' do
+ it '107. Make a form with input_submit(value)' do
out = form_for(@data, :method => :get) do |f|
f.input_submit 'Send'
end
@@ -202,7 +1118,7 @@ def assert(expected, output)
# ------------------------------------------------
# Checkboxes
- it 'Make a form with input_checkbox(label, name)' do
+ it '108. Make a form with input_checkbox(label, name)' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned
end
@@ -218,7 +1134,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox(label, name, checked)' do
+ it '109. Make a form with input_checkbox(label, name, checked)' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned, 'bacon'
end
@@ -234,7 +1150,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox(label, name, checked, values, default)' do
+ it '110. Make a form with input_checkbox(label, name, checked, values, default)' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned, 'boo', :values => ['boo']
end
@@ -249,7 +1165,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox and check multiple values using an array' do
+ it '111. Make a form with input_checkbox and check multiple values using an array' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned, ['boo'], :values => ['boo', 'foo']
end
@@ -265,7 +1181,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox and check multiple values using a hash' do
+ it '112. Make a form with input_checkbox and check multiple values using a hash' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned, ['boo'], :values => {'Boo' => 'boo'}
end
@@ -280,7 +1196,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox(label, name) but hide the value of the checkbox' do
+ it '113. Make a form with input_checkbox(label, name) but hide the value of the checkbox' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned, nil, :show_value => false
end
@@ -296,7 +1212,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox(label, name) but hide thelabel' do
+ it '114. Make a form with input_checkbox(label, name) but hide the label' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned, nil, :show_label => false
end
@@ -314,7 +1230,7 @@ def assert(expected, output)
# ------------------------------------------------
# Checkboxes using a hash
- it 'Make a form with input_checkbox(label, name) using a hash' do
+ it '115. Make a form with input_checkbox(label, name) using a hash' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned_hash
end
@@ -330,7 +1246,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_checkbox(label, name, checked) using a hash' do
+ it '116. Make a form with input_checkbox(label, name, checked) using a hash' do
out = form_for(@data, :method => :get) do |f|
f.input_checkbox 'Assigned', :assigned_hash, 'bacon'
end
@@ -349,7 +1265,7 @@ def assert(expected, output)
# ------------------------------------------------
# Radio buttons
- it 'Make a form with input_radio(label, name)' do
+ it '117. Make a form with input_radio(label, name)' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned
end
@@ -365,7 +1281,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_radio(label, name, checked)' do
+ it '118. Make a form with input_radio(label, name, checked)' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned, 'bacon'
end
@@ -381,7 +1297,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_radio(label, name, checked, values, default)' do
+ it '119. Make a form with input_radio(label, name, checked, values, default)' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned, 'boo', :values => ['boo']
end
@@ -396,7 +1312,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_radio(label, name) but hide the value' do
+ it '120. Make a form with input_radio(label, name) but hide the value' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned, nil, :show_value => false
end
@@ -412,7 +1328,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_radio(label, name) but hide the label' do
+ it '121. Make a form with input_radio(label, name) but hide the label' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned, nil, :show_label => false
end
@@ -431,7 +1347,7 @@ def assert(expected, output)
# ------------------------------------------------
# Radio buttons using a hash
- it 'Make a form with input_radio(label, name) using a hash' do
+ it '122. Make a form with input_radio(label, name) using a hash' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned_hash
end
@@ -447,7 +1363,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_radio(label, name, checked) using a hash' do
+ it '123. Make a form with input_radio(label, name, checked) using a hash' do
out = form_for(@data, :method => :get) do |f|
f.input_radio 'Assigned', :assigned_hash, 'bacon'
end
@@ -466,7 +1382,7 @@ def assert(expected, output)
# ------------------------------------------------
# File uploading
- it 'Make a form with input_file(label, name)' do
+ it '124. Make a form with input_file(label, name)' do
out = form_for(@data, :method => :get) do |f|
f.input_file 'File', :file
end
@@ -481,7 +1397,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_file(label, name)' do
+ it '125. Make a form with input_file(label, name)' do
out = form_for(@data, :method => :get) do |f|
f.input_file 'File', :file, :id => 'awesome_file'
end
@@ -499,7 +1415,19 @@ def assert(expected, output)
# ------------------------------------------------
# Hidden fields
- it 'Make a form with input_hidden(name, value)' do
+ it '125. Make a form with input_hidden(name)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_hidden :username
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '126. Make a form with input_hidden(name, value)' do
out = form_for(@data, :method => :get) do |f|
f.input_hidden :username, 'Bob Ross'
end
@@ -511,7 +1439,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with input_hidden(name, value, id)' do
+ it '127. Make a form with input_hidden(name, value, id)' do
out = form_for(@data, :method => :get) do |f|
f.input_hidden :username, 'Bob Ross', :id => 'test'
end
@@ -526,7 +1454,7 @@ def assert(expected, output)
# ------------------------------------------------
# Textarea elements
- it 'Make a form with textarea(label, name)' do
+ it '128. Make a form with textarea(label, name)' do
out = form_for(@data, :method => :get) do |f|
f.textarea 'Message', :message
end
@@ -541,7 +1469,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with textarea(label, name, value)' do
+ it '129. Make a form with textarea(label, name, value)' do
out = form_for(@data, :method => :get) do |f|
f.textarea 'Message', :message, :value => 'stuff'
end
@@ -559,7 +1487,7 @@ def assert(expected, output)
# ------------------------------------------------
# Select elements
- it 'Make a form with select(label, name) from a hash' do
+ it '130. Make a form with select(label, name) from a hash' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_hash
end
@@ -578,7 +1506,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with select(label, name, selected) from a hash' do
+ it '131. Make a form with select(label, name, selected) from a hash' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_hash, :selected => :mongrel
end
@@ -597,7 +1525,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with select(label, name) from an array' do
+ it '132. Make a form with select(label, name) from an array' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_array
end
@@ -616,7 +1544,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with select(label, name, selected) from an array' do
+ it '133. Make a form with select(label, name, selected) from an array' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_array, :selected => 'Mongrel'
end
@@ -638,7 +1566,7 @@ def assert(expected, output)
# ------------------------------------------------
# Select elements with custom values
- it 'Make a form with select(label, name) from a hash using custom values' do
+ it '134. Make a form with select(label, name) from a hash using custom values' do
out = form_for(@data, :method => :get) do |f|
f.select 'People', :people_hash, :values => {:chuck => 'Chuck', :bob => 'Bob'}
end
@@ -656,7 +1584,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with select(label, name, selected) from a hash using custom values' do
+ it '135. Make a form with select(label, name, selected) from a hash using custom values' do
out = form_for(@data, :method => :get) do |f|
f.select 'People', :people_hash, :values => {:chuck => 'Chuck', :bob => 'Bob'}, :selected => :chuck
end
@@ -674,7 +1602,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with select(label, name) from an array using custom values' do
+ it '136. Make a form with select(label, name) from an array using custom values' do
out = form_for(@data, :method => :get) do |f|
f.select 'People', :people_array, :values => ['Chuck', 'Bob']
end
@@ -692,7 +1620,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with select(label, name, selected) from an array using custom values' do
+ it '137. Make a form with select(label, name, selected) from an array using custom values' do
out = form_for(@data, :method => :get) do |f|
f.select 'People', :people_array, :values => ['Chuck', 'Bob'], :selected => 'Chuck'
end
@@ -710,7 +1638,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with multiple select(label, name) from a hash' do
+ it '138. Make a form with multiple select(label, name) from a hash' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_hash, :multiple => :multiple
end
@@ -729,7 +1657,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with multiple select(label, name, selected) from a hash' do
+ it '139. Make a form with multiple select(label, name, selected) from a hash' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_hash, :multiple => :multiple, :selected => :webrick
end
@@ -748,7 +1676,7 @@ def assert(expected, output)
FORM
end
- it 'Make a form with multiple select(label, name, selected) from a hash' do
+ it '140. Make a form with multiple select(label, name, selected) from a hash' do
out = form_for(@data, :method => :get) do |f|
f.select 'Server', :servers_hash, :multiple => :multiple, :selected => [:webrick, :mongrel]
end
@@ -767,10 +1695,214 @@ def assert(expected, output)
FORM
end
+ # ------------------------------------------------
+ # HTML5 Extensions
+
+ it '141. Make a form with input_button(label, value) with JavaScript call' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_button 'Accept', :onclick=>'fcn()'
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '142. Make a form with input_color(label, name)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_color 'Choose a color', :my_color
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '142. Make a form with input_email(label, value)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_email 'Email', :email
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '144. Make a form with input_image()' do
+ out = form_for(@data, :method => :get) do |f|
+ f.image "http://www.w3schools.com/tags/img_submit.gif", :alt=>"Submit"
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '145. Make a form with input_number(label, value)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_number 'Age', :age, :min=>1, :max=>120
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '146. Make a form with input_range(label, value)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_range 'Cost', :cost, :min=>0, :max=>100
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '147. Make a form with input_reset()' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_reset
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '148. Make a form with input_reset(value)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_reset 'Reset'
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '149. Make a form with input_url(label, value)' do
+ out = form_for(@data, :method => :get) do |f|
+ f.input_url 'URL', :url
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ # ------------------------------------------------
+ # Verify that select boxes reload from the form object
+
+ it '150. Make a form with select(label, name, selected) take from form object' do
+ @data.person = "chuck"
+ out = form_for(@data, :method => :get) do |f|
+ f.select 'Person', :person, :values => {'chuck' => 'Chuck', 'bob' => 'Bob'}
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ it '151. Make a form with select(label, name, selected) take from form object' do
+ @data.person = "chuck"
+ out = form_for(@data, :method => :get) do |f|
+ form_error(:person, "This person has not validated his email.")
+ f.select 'Person', :person, :values => {'chuck' => 'Chuck', 'bob' => 'Bob'}
+ end
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
+ # ------------------------------------------------
+ # Code used in documentation
+
+ it '160. Test error posting' do
+ params = {:username=>"gladys", :password=>"abc", :gender=>"F", :country=>"SV"}
+ user = UserX.new
+ user.set_fields(params, [:username, :password, :gender, :country], :missing=>:skip)
+ user.errors[:username] = "User not in system"
+ user.errors[:password] = "The username/password combination is not on our system"
+ out = form_for(user, :method=>:post, :action=>:login2) do |f|
+ f.text("Username: ", :username)
+ f.password("Password: ", :password)
+ end.to_html
+
+ assert(<<-FORM, out)
+
+ FORM
+ end
+
# ------------------------------------------------
# Error messages
- it 'Insert an error message' do
+ it '198. Insert an error message' do
form_error :username, 'May not be empty'
out = form_for(@data, :method => :get) do |f|
f.input_text 'Username', :username
@@ -779,17 +1911,17 @@ def assert(expected, output)
assert(<<-FORM, out)
FORM
end
- it 'Retrieve all errors messages from the model' do
+ it '199. Retrieve all errors messages from the model' do
@data.errors = {:username => "May not be empty"}
form_errors_from_model(@data)
-
out = form_for(@data, :method => :get) do |f|
f.input_text 'Username', :username
end
@@ -797,8 +1929,9 @@ def assert(expected, output)
assert(<<-FORM, out)
FORM
diff --git a/spec/ramaze/scaffolding.rb b/spec/ramaze/scaffolding.rb
new file mode 100644
index 00000000..ac524baa
--- /dev/null
+++ b/spec/ramaze/scaffolding.rb
@@ -0,0 +1,268 @@
+# * Encoding: UTF-8
+#
+# Copyright (c) 2009 Michael J. Welch, Ph.D. mjwelchphd@gmail.com
+# All files in this distribution are subject to the terms of the MIT license.
+
+require 'sqlite3'
+require 'sequel'
+
+require File.expand_path('../../../spec/helper', __FILE__)
+
+require 'ramaze/scaffolding'
+
+# create some test data
+DB = Sequel.sqlite
+DB::drop_table?(:coltypes)
+DB::create_table(:coltypes) do # common database type used
+ primary_key :id # int(11) + primary key
+ Integer :int11 # int(11)
+ String :vc255 # varchar(255)
+ String :vc50, :size=>50 # varchar(50)
+ String :c255, :fixed=>true # char(255)
+ String :c50, :fixed=>true, :size=>50 # char(50)
+ String :text, :text=>true # text
+ File :blob # blob
+ Fixnum :fixnum # int(11)
+ Bignum :bignum # bigint(20)
+ Float :dblflt # double
+ BigDecimal :bigdec # decimal(10,0)
+ BigDecimal :big6dec, :size=>6 # decimal(6,0)
+ BigDecimal :big10dec2, :size=>[10, 2] # decimal(10,2)
+ Date :justdate # date
+ DateTime :datetime # datetime
+ Time :justtime # datetime
+ Time :timeonly, :only_time=>true # time
+ Numeric :numeric # decimal(10,0)
+ TrueClass :booltrue # tinyint(1)
+ FalseClass :boolfalse # tinyint(1)
+ DateTime :created_at # datetime
+ DateTime :updated_at # datetime
+end
+dataset = DB[:coltypes]
+dataset.insert(:vc255=>"Coco", :text=>"Species: Cocosaurus Rex", :blob=>"Good bird!", :created_at=>Time.now, :updated_at=>Time.now)
+
+describe 'Ramaze::Scaffolding' do
+
+known_code = <\"/coltype/new\") { \"new\" }
+ end
+ @g.table do
+ # create the heading
+ @g.tr do
+ @index_columns.each do |col|
+ @g.td do
+ @g.strong { col.to_s.titleize }
+ end
+ end
+ end
+ # list all the rows
+ rows.each do |row|
+ @g.tr do
+ row.each do |col,value|
+ @g.td { value.to_s }
+ end
+ @g.td do
+ @g.a(:href=>\"/coltype/show?id=%s\"%row[:id]) { \"show\" }
+ @g << \" | \"
+ @g.a(:href=>\"/coltype/edit?id=%s\"%row[:id]) { \"edit\" }
+ @g << \" | \"
+ @g.a(:href=>\"/coltype/show?id=%s&delete\"%row[:id]) { \"delete\" }
+ end
+ end
+ end
+ end
+ end
+ @g.to_s
+ end
+
+ def new
+ @g = Ramaze::Gestalt.new
+ @title = \"New Coltype\"
+ @g.scaffolding do
+ @g.h3 { @title }
+ row = Coltype.new
+ @g.form(:method=>:post, :action=>:save_new) do
+ @g.table do
+ @g.tr do
+ @g.td { @g.strong { \"Id\" } }
+ @g.td do
+ opts = @g.input(:type=>:number, :name=>:id, :value=>row[:id], :size=>11, :id=>\"form_id\")
+ end
+ end
+ @g.tr do
+ @g.td { @g.strong { \"Vc255\" } }
+ @g.td do
+ @g.input(:type=>:text, :name=>:vc255, :value=>row[:vc255], :size=>32, :id=>\"form_vc255\")
+ end
+ end
+ @g.tr do
+ @g.td { @g.strong { \"Int11\" } }
+ @g.td do
+ opts = @g.input(:type=>:number, :name=>:int11, :value=>row[:int11], :size=>11, :id=>\"form_int11\")
+ end
+ end
+ end
+ @g.br
+ @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Back\")
+ @g << \" \"
+ @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Save\")
+ end
+ end
+ @g.to_s
+ end
+
+ def show
+ @g = Ramaze::Gestalt.new
+ @title = \"Show Coltype\"
+ @g.scaffolding do
+ @g.h3 { @title }
+ row = Coltype.where(:id=>session.request.params['id']).first
+ @g.form(:method=>:post, :action=>:save_show) do
+ @g.input(:type=>:hidden, :name=>:id, :value=>row.id)
+ @g.table do
+ @g.tr do
+ @g.td { @g.strong { \"Id\" } }
+ @g.td do
+ opts = @g.input(:type=>:number, :name=>:id, :value=>row[:id], :size=>11, :id=>\"form_id\", :disabled=>true)
+ end
+ end
+ @g.tr do
+ @g.td { @g.strong { \"Vc255\" } }
+ @g.td do
+ @g.input(:type=>:text, :name=>:vc255, :value=>row[:vc255], :size=>32, :id=>\"form_vc255\", :disabled=>true)
+ end
+ end
+ @g.tr do
+ @g.td { @g.strong { \"Int11\" } }
+ @g.td do
+ opts = @g.input(:type=>:number, :name=>:int11, :value=>row[:int11], :size=>11, :id=>\"form_int11\", :disabled=>true)
+ end
+ end
+ end
+ @g.br
+ @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Back\")
+ if session.request.params.has_key?('delete')
+ @g << \" \"
+ @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Delete\")
+ end
+ end
+ end
+ @g.to_s
+ end
+
+ def edit
+ @g = Ramaze::Gestalt.new
+ @title = \"Edit Coltype\"
+ @g.scaffolding do
+ @g.h3 { @title }
+ row = Coltype.where(:id=>session.request.params['id']).first
+ row.updated_at = Time.now
+ @g.form(:method=>:post, :action=>:save_edit) do
+ @g.input(:type=>:hidden, :name=>:id, :value=>row.id)
+ @g.table do
+ @g.tr do
+ @g.td { @g.strong { \"Id\" } }
+ @g.td do
+ opts = @g.input(:type=>:number, :name=>:id, :value=>row[:id], :size=>11, :id=>\"form_id\")
+ end
+ end
+ @g.tr do
+ @g.td { @g.strong { \"Vc255\" } }
+ @g.td do
+ @g.input(:type=>:text, :name=>:vc255, :value=>row[:vc255], :size=>32, :id=>\"form_vc255\")
+ end
+ end
+ @g.tr do
+ @g.td { @g.strong { \"Int11\" } }
+ @g.td do
+ opts = @g.input(:type=>:number, :name=>:int11, :value=>row[:int11], :size=>11, :id=>\"form_int11\")
+ end
+ end
+ end
+ @g.br
+ @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Back\")
+ @g << \" \"
+ @g.input(:type=>:submit, :id=>\"goto\", :name=>\"goto\", :value=>\"Save\")
+ end
+ end
+ @g.to_s
+ end
+
+ def save_new
+ if session.request.params['goto']==\"Save\"
+ row = Coltype.new
+ row.set_fields(session.request.params, @new_columns, :missing=>:skip)
+ row.id = nil
+ row.created_at = Time.now if @columns.index(:created_at)
+ row.updated_at = Time.now if @columns.index(:updated_at)
+ row.save
+ end
+ redirect(\"/coltype/index\")
+ end
+
+ def save_show
+ if session.request.params['goto']==\"Delete\"
+ row = Coltype.where(:id=>session.request.params['id']).first
+ row.delete
+ end
+ redirect(\"/coltype/index\")
+ end
+
+ def save_edit
+ if session.request.params['goto']==\"Save\"
+ row = Coltype.where(:id=>session.request.params['id']).first
+ row.set_fields(session.request.params, @edit_columns, :missing=>:skip)
+ row.updated_at = Time.now if @columns.index(:updated_at)
+ row.save
+ redirect(\"/coltype/index\")
+ end
+ redirect(\"/coltype/index\")
+ end
+
+end
+END_TEXT
+
+ it "should create a CRUD controller for ColtypeController" do
+ test_code = Ramaze::Scaffolding.new.build_controller(
+ :model=>:coltype,
+ :index_columns=>[:id, :vc255, :int11],
+ :new_columns=>[:id, :vc255, :int11],
+ :show_columns=>[:id, :vc255, :int11],
+ :edit_columns=>[:id, :vc255, :int11]
+ )
+ known_code_lines = known_code.split("\n")
+ test_code_lines = test_code.split("\n")
+
+ n = known_code_lines.size
+ 0.upto(n-1) do |i|
+ known_code_lines[i].should == test_code_lines[i]
+ end
+
+ end
+
+end