SephirothSpawn
Sponsor
Version 1.0
Description:
The idea behind this script was simply: How could I create a data struct class, container class, and make creating these objects easy? The result was a module to generate both Ruby code that creates the Ruby data struct class, creates the container and everything for you. Additionally, a nice little html page that generates the Ruby code for creation of all the objects. More additionally, it organizes your containers for you, auto-increases object id instances, and adds the option to save and load objects into rxdata files!
The Script:
Can you believe all this power in a script under 400 lines for coding, with comments included?
Code:
#==============================================================================
# ** Data Structure Generator
#------------------------------------------------------------------------------
# SephirothSpawn
# Version 1.0
# 2010-01-27
#------------------------------------------------------------------------------
# * Details
#
# This script was designed to auto-generate data structures and make a nice
# like html form to allow non-scripters to create these new objects with
# no scripting required! So any non-scripter can make can not only create
# data structures, but create an entire database!
#
# This cannot be easier (and I challenge anyone)!
#
# The object class is generated auto-matically. The container object is added
# to a pre-set DSG object ($data_dsg). The generated Ruby code also
# adds the option to save and load the objects from rxdata files as well.
#
# The class generated will always be a child class of DSG::Data_Object.
# Why? The parent class serves 2 functions:
#
# 1) Auto-Set an ID instance variable that increases by 1 after each object
# is created
# 2) Auto-Sets object directly into the container. You will never need to
# set the object into $data container.
#
#
# A HTML page with a form is generated for users to generate Ruby code to
# create the objects into the data structure. Users fill out this form and
# Ruby code is generated for you.
#------------------------------------------------------------------------------
# * Generating Ruby Data Struct class and HTML form
#
# 1) Insert a new area into the script list
# 2) Start Data Struct - Add this line
# DSG.start(class_name, rxdata_name, container_name)
#
# Replace class_name with a Ruby class name (ie: 'Card')
# Replace rxdata with data filename (ie: 'Cards.rxdata')
# Replace container name (ie: 'cards')
# 3) Add required instances (instances that are passed in the initialization)
#
# For each required instance, add this line:
#
# DSG.add_req_instance(instance_name, description, default, type)
#
# Replace instance_name with your instances name (ie: 'suit')
# Replace description with a simple description for instance (ie: 'Suit')
# Replace default with default value (ie: 'Hearts')
# Replace type with Ruby type for values (ie: 'String')
#
# * Note that the default is only used for HTML form fields
#
# 4) Add optional instances (instances not specified in the initialization)
#
# For each instance, add this line:
#
# DSG.add_instance(instance_name, description, default, type)
#
# * See step 3 for replacement instructions
# * Note that the default value is specified in object class init.
#
# 5) Finish Data Struct - Add this line of code:
# DSG.finish(ruby_name, html_name)
#
# Replace ruby_name with .txt file generated with object class code
# (ie: 'Card.txt') (Defaults to 'Generate.txt')
# Replace html_name with .html file form (ie: 'Card.html')
# (Defaults to 'Generate.html')
#
# 6) The code generated in the .txt file is your Ruby code to insert into
# script editor.
#
# 7) Open the .html file and complete the form. For each object, press the
# Add Item button. When finished, copy and paste code into your first
# generated code between the lines:
#
# # Insert Database Modifications Here
# <Insert HTML Generated Code Here>
# # Stop Modifications
#==============================================================================
#==============================================================================
# ** Data Structure Generator
#==============================================================================
module DSG
#--------------------------------------------------------------------------
# * Start
#--------------------------------------------------------------------------
def self.start(class_name, rxdata_name, container_name)
@class_name = class_name
@rxdata_name = rxdata_name
@container_name = container_name
@required_instances = {}
@instances = {}
end
#--------------------------------------------------------------------------
# * Add Required Instance
#--------------------------------------------------------------------------
def self.add_req_instance(instance_name, description, default, type)
@required_instances[instance_name] = [description, default, type]
end
#--------------------------------------------------------------------------
# * Add Instance
#--------------------------------------------------------------------------
def self.add_instance(instance_name, description, default, type)
@instances[instance_name] = [description, default, type]
end
#--------------------------------------------------------------------------
# * Finish
#--------------------------------------------------------------------------
def self.finish(ruby_name = 'Generate.txt', html_name = 'Generate.html')
# Generate Data Structure Ruby Code
self.generate_ruby_data_struct(ruby_name)
# Generate HTML Sheet Field
self.generate_html_form(html_name)
end
#--------------------------------------------------------------------------
# * Generate Data Structure Ruby Code
#--------------------------------------------------------------------------
def self.generate_ruby_data_struct(ruby_name)
# Start Line Code
s = []
s << '#=============================================================================='
s << '# ** Load Rxdata (Set to false when change in database)'
s << '#=============================================================================='
s << ''
s << 'module DSG'
s << " Load_#{@container_name.capitalize} = false"
s << 'end'
s << ''
s << '#=============================================================================='
s << "# ** #{@class_name}"
s << '#=============================================================================='
s << ''
s << "class #{@class_name} < DSG::Data_Object"
s << ' #--------------------------------------------------------------------------'
s << ' # * Public Instance Variables'
s << ' #--------------------------------------------------------------------------'
(@instances.keys + @required_instances.keys).sort.each do |instance_name|
s << " attr_accessor :#{instance_name}"
end
s << ' #--------------------------------------------------------------------------'
s << ' # * Object Initialization'
s << ' #--------------------------------------------------------------------------'
s << " def initialize(#{@required_instances.keys.sort.join(', ')})"
s << ' super()'
@required_instances.keys.sort.each do |instance_name|
s << " @#{instance_name} = #{instance_name}"
end
@instances.keys.sort.each do |instance_name|
default = @instances[instance_name][1]
s << " @#{instance_name} = #{self.object_to_string(default)}"
end
s << ' end'
s << 'end'
s << ''
s << '# Creates Container Object'
s << "$data_dsg.add_container('#{@container_name}')"
s << "DSG::Containers.module_eval('attr_reader :#{@container_name}')"
s << "DSG::Data_Object.module_eval(\"@@container_objects[#{@class_name}] = '#{@container_name}'\")"
s << ''
s << '#=============================================================================='
s << '# ** Load or Create Database'
s << '#=============================================================================='
s << ''
s << "if DSG::Load_#{@container_name.capitalize}"
s << " $data_dsg.#{@container_name} = load_data('Data/#{@rxdata_name}')"
s << 'else'
s << ''
s << '# Insert Database Modifications Here'
s << ''
s << '# Stop Modifications'
s << ''
s << '# Save Data File'
s << "save_data($data_dsg.#{@container_name}, 'Data/#{@rxdata_name}')"
s << ''
s << 'end'
# Write Ruby Code
file = File.new(ruby_name, 'w+')
s.each {|l| file.write("#{l}\n")}
file.close
end
#--------------------------------------------------------------------------
# * Generate HTML Doc Form
#--------------------------------------------------------------------------
def self.generate_html_form(html_name)
# Start Line Code
s = []
s << '<html>'
s << '<head>'
s << '<meta http-equiv="Content-Language" content="en-us">'
s << '<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">'
s << '<title>Data Structure Generator 1.0</title>'
s << '<script type="text/javascript">'
s << ''
s << '// * Variable Decloration'
s << "var class_name = '#{@class_name}'"
@instances.keys.sort.each do |instance_name|
default = @instances[instance_name][1]
s << "var #{instance_name}_default = #{self.object_to_string(default)}"
end
s << ''
s << 'function AddItem() {'
s << ''
s << '// Get Current Code'
s << 'text = document.form1.textarea.value'
s << ''
s << '// Add Comment'
s << "text += '# ' + document.form1.object_coment.value"
s << 'text += "\n"'
s << ''
s << '// Create Object'
s << "text += class_name + '.new('"
if @required_instances.size > 0
s << '// Add Required Items'
@required_instances.keys.sort.each do |instance_name|
s << "text += document.form1.#{instance_name}.value"
if instance_name != @required_instances.keys.sort.last
s << 'text += ", "'
end
end
s << '// Finish Required Items'
end
s << 'text += ")\n"'
s << ''
if @instances.size > 0
s << '// Modify Instances Comparing Defaults'
@instances.keys.sort.each do |instance_name|
s << "value = document.form1.#{instance_name}.value"
s << "if (value != #{instance_name}_default) {"
s << " text += 'object.#{instance_name} = ' + value"
s << ' text += "\n"'
s << '}'
end
s << ''
end
s << '// Write Text'
s << 'document.form1.textarea.value = text'
s << '}'
s << '</script>'
s << '</head>'
s << ''
s << '<body text="#FFFFFF">'
s << ''
s << '<div align="center">'
s << ' <form action="" method="POST" name="form1" id="form1">'
s << ' <table border="1" cellspacing="3" cellpadding="5" bordercolor="#111111" width="600" bgcolor="#808080">'
s << ' <tr>'
s << ' <th colspan="3" bgcolor="#333333"><font size="5">Data Structure Generator 1.0</font></th>'
s << ' </tr>'
s << ' <tr>'
s << ' <td colspan="2" bgcolor="505050">Comment Heading (To Seperate Items)</td>'
s << ' <td bgcolor="505050"><input type="text" name="object_coment" size="20" value="New Item" /></td>'
s << ' </tr>'
if @required_instances.size > 0
s << ' <tr>'
s << ' <th colspan="3" bgcolor="#444444"><font size="4">Required Settings</font></th>'
s << ' </tr>'
s << ' <tr>'
s << ' <!-- Start Required Instance Fields -->'
@required_instances.keys.sort.each do |instance_name|
s << ' <tr>'
s << " <td width='30%'>#{@required_instances[instance_name][0]}</td>"
s << " <td align='center' width='35%'><input type='text' name='#{instance_name}' size='20' value='#{@required_instances[instance_name][1]}'><br><font size='1'>#{instance_name}</font></td>"
s << " <td width='35%'>Default: #{@required_instances[instance_name][1]} (#{@required_instances[instance_name][2]})</td>"
s << ' </tr>'
end
s << ' <!-- End Required Instance Fields -->'
end
if @instances.size > 0
s << ' <tr>'
s << ' <th colspan="3" bgcolor="#444444"><font size="4">Optional Settings</font></th>'
s << ' </tr>'
s << ' <!-- Start Instance Fields -->'
@instances.keys.sort.each do |instance_name|
s << ' <tr>'
s << " <td width='30%'>#{@instances[instance_name][0]}</td>"
s << " <td align='center' width='35%'><input type='text' name='#{instance_name}' size='20' value='#{@instances[instance_name][1]}'><br><font size='1'>#{instance_name}</font></td>"
s << " <td width='35%'>Default: #{@instances[instance_name][1]} (#{@instances[instance_name][2]})</td>"
s << ' </tr>'
end
s << ' <!-- End Instance Fields -->'
end
s << ' <tr>'
s << ' <td colspan="3" bgcolor="#222222" align="center" ><input type="button" name="Submit" value="Add Item" onclick="AddItem()" /></td>'
s << ' </tr>'
s << ' <tr>'
s << ' <td colspan="3" bgcolor="#FFFFFF">'
s << ' <label>'
s << ' <textarea name="textarea" cols="70" rows="10" wrap="physical" value=""></textarea>'
s << ' </label>'
s << ' </td>'
s << ' </tr>'
s << ' </table>'
s << ' </form>'
s << '</div>'
s << ''
s << '</body>'
s << ''
s << '</html>'
# Write HTML Code
file = File.new(html_name, 'w+')
s.each {|l| file.write("#{l}\n")}
file.close
end
#--------------------------------------------------------------------------
# * Object to String
#--------------------------------------------------------------------------
def self.object_to_string(object)
case object
when Array
object.collect! {|o| self.object_to_string(o)}
return "[#{object.join(', ')}]"
when Hash
array = []
default.each do |k, v|
k_string = self.object_to_string(k)
v_string = self.object_to_string(v)
array << "#{k} => #{v}"
end
return "{#{array.join(', ')}}"
when String
return "'#{object}'"
else
return object
end
end
end
#==============================================================================
# ** DSG::Data_Object
#==============================================================================
class DSG::Data_Object
#--------------------------------------------------------------------------
# * Container Objects
#--------------------------------------------------------------------------
@@container_objects = {}
#--------------------------------------------------------------------------
# * Object ID#s (Auto-Counter)
#--------------------------------------------------------------------------
@@ids = {}
#--------------------------------------------------------------------------
# * Public Instance Variable
#--------------------------------------------------------------------------
attr_accessor :id
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
# Create Class Counter (If not defined)
@@ids[self.class] = 0 unless @@ids.has_key?(self.class)
# Add class counter
@@ids[self.class] += 1
# Set ID
@id = @@ids[self.class]
# Add object to container
eval "$data_dsg.#{@@container_objects[self.class]}[@id] = self"
end
end
#==============================================================================
# ** Data Structure Generator::Containers
#==============================================================================
class DSG::Containers
#--------------------------------------------------------------------------
# * Add Container
#--------------------------------------------------------------------------
def add_container(instance_name)
eval "@#{instance_name} = {}"
end
end
$data_dsg = DSG::Containers.new
Example:
Take for instance, something like my Triple Triad script. The following would create a class for these with the basic 4 powers and element for the cards. It would save them in a container $data_dsg.cards.
Code:
DSG.start('Card', 'Cards.rxdata', 'cards')
stats = {
'np' => 'North Power',
'ep' => 'East Power',
'sp' => 'South Power',
'wp' => 'West Power',
}
stats.each do |stat, string|
DSG.add_req_instance("#{stat}", "#{string}", 1, 'Integer')
end
DSG.add_instance('element', 'Element', 0, 'Integer')
DSG.finish
Running this code would end up generating this Ruby code for you:
Code:
#==============================================================================
# ** Load Rxdata (Set to false when change in database)
#==============================================================================
module DSG
Load_Cards = false
end
#==============================================================================
# ** Card
#==============================================================================
class Card < DSG::Data_Object
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :element
attr_accessor :ep
attr_accessor :np
attr_accessor :sp
attr_accessor :wp
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize(ep, np, sp, wp)
super()
@ep = ep
@np = np
@sp = sp
@wp = wp
@element = 0
end
end
# Creates Container Object
$data_dsg.add_container('cards')
DSG::Containers.module_eval('attr_reader :cards')
DSG::Data_Object.module_eval("@@container_objects[Card] = 'cards'")
#==============================================================================
# ** Load or Create Database
#==============================================================================
if DSG::Load_Cards
$data_dsg.cards = load_data('Data/Cards.rxdata')
else
# Insert Database Modifications Here
# Stop Modifications
# Save Data File
save_data($data_dsg.cards, 'Data/Cards.rxdata')
end
How neat? It would also generate a html page for you. Fill out the form, create your objects, copy and page and the code is done.
All objects could simply by accessed via:
Code:
$data_dsg.cards[card_id]
Author Notes:
I am all up for suggestions to make this easier, or questions on how to use this. Other than that...
Enjoy!