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: +

+ + + +

+ For more information, check out ramaze.net and + the documentation. +
+ You can also read the + YARD documentation + or browse around the Ramaze source code. +

+ +

+ For help with Ramaze, visit + #ramaze on irc.freenode.net. +
+ You can use Mibbit, + an AJAX based IRC client or + + the official freenode irc java applet + . +

+ +

+ 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: +

+ + + +

+ For more information, check out ramaze.net and + the documentation. +
+ You can also read the + YARD documentation + or browse around the Ramaze source code. +

+ +

+ For help with Ramaze, visit + #ramaze on irc.freenode.net. +
+ You can use Mibbit, + an AJAX based IRC client or + + the official freenode irc java applet + . +

+ +

+ 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] == '') + # 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) +
+
+ The Form +
+
+ 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) +
+

+ + bacon + steak +

+
+ 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) +
+

+ + bacon + steak +

+
+ 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) +
+

+ + boo +

+
+ 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) +
+

+ + boo + foo +

+
+ 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) +
+

+ + Boo +

+
+ 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) +
+

+ bacon + steak +

+
+ 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) +
+

+ + Bacon + Steak +

+
+ 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) +
+

+ + Bacon + Steak +

+
+ 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) +
+

+ + bacon + steak +

+
+ 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) +
+

+ + bacon + steak +

+
+ 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) +
+

+ + boo +

+
+ 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) +
+

+ bacon + steak +

+
+ 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) +
+

+ + Bacon + Steak +

+
+ 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) +
+

+ + Bacon + Steak +

+
+ 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)
-
- The Form -
+

+ + +

+
+ 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) +
+

+ + +  User not in system +

+

+ + +  The username/password combination is not on our system +

+
+ 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) +
+

+ + +  May not be empty +

+
+ 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) +
+

+ + +  May not be empty +

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) +
+

+ + +  User not in system +

+

+ + +  The username/password combination is not on our system +

+
+ 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)

- - + + +  May not be empty

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)

- - + + +  May not be empty

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