Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Imported KirbyBase 2.6

  • Loading branch information...
commit ee03978e5b248d1ba559fb73348bc19a9be4d660 0 parents
@weppos authored
Showing with 12,938 additions and 0 deletions.
  1. +67 −0 README
  2. +18 −0 bin/kbserver.rb
  3. +144 −0 changes.txt
  4. +237 −0 examples/aaa_try_this_first/kbtest.rb
  5. +27 −0 examples/add_column_test/add_column_test.rb
  6. +51 −0 examples/calculated_field_test/calculated_field_test.rb
  7. +25 −0 examples/change_column_type_test/change_column_type_test.rb
  8. +44 −0 examples/column_required_test/column_required_test.rb
  9. +100 −0 examples/crosstab_test/crosstab_test.rb
  10. +31 −0 examples/csv_import_test/csv_import_test.rb
  11. +11 −0 examples/csv_import_test/plane.csv
  12. +54 −0 examples/default_value_test/default_value_test.rb
  13. +24 −0 examples/drop_column_test/drop_column_test.rb
  14. +46 −0 examples/indexes_test/add_index_test.rb
  15. +66 −0 examples/indexes_test/drop_index_test.rb
  16. +94 −0 examples/indexes_test/index_test.rb
  17. +47 −0 examples/kbserver_as_win32_service/kbserver_daemon.rb
  18. +75 −0 examples/kbserver_as_win32_service/kbserverctl.rb
  19. +70 −0 examples/link_many_test/link_many_test.rb
  20. +55 −0 examples/lookup_field_test/lookup_field_test.rb
  21. +62 −0 examples/lookup_field_test/lookup_field_test_2.rb
  22. +69 −0 examples/lookup_field_test/the_hal_fulton_feature_test.rb
  23. +65 −0 examples/many_to_many_test/many_to_many_test.rb
  24. +74 −0 examples/memo_test/memo_test.rb
  25. 0  examples/memo_test/memos/blank.txt
  26. +77 −0 examples/record_class_test/record_class_test.rb
  27. +38 −0 examples/record_class_test/record_class_test2.rb
  28. +46 −0 examples/rename_column_test/rename_column_test.rb
  29. +38 −0 examples/rename_table_test/rename_table_test.rb
  30. +47 −0 examples/yaml_field_test/yaml_field_test.rb
  31. BIN  images/blank.png
  32. BIN  images/callouts/1.png
  33. BIN  images/callouts/10.png
  34. BIN  images/callouts/11.png
  35. BIN  images/callouts/12.png
  36. BIN  images/callouts/13.png
  37. BIN  images/callouts/14.png
  38. BIN  images/callouts/15.png
  39. BIN  images/callouts/2.png
  40. BIN  images/callouts/3.png
  41. BIN  images/callouts/4.png
  42. BIN  images/callouts/5.png
  43. BIN  images/callouts/6.png
  44. BIN  images/callouts/7.png
  45. BIN  images/callouts/8.png
  46. BIN  images/callouts/9.png
  47. BIN  images/caution.png
  48. BIN  images/client_server.png
  49. BIN  images/example.png
  50. BIN  images/home.png
  51. BIN  images/important.png
  52. BIN  images/kirby1.jpg
  53. BIN  images/next.png
  54. BIN  images/note.png
  55. BIN  images/prev.png
  56. BIN  images/single_user.png
  57. BIN  images/smallnew.png
  58. BIN  images/tip.png
  59. BIN  images/toc-blank.png
  60. BIN  images/toc-minus.png
  61. BIN  images/toc-plus.png
  62. BIN  images/up.png
  63. BIN  images/warning.png
  64. +8 −0 install.rb
  65. +2,324 −0 kirbybaserubymanual.html
  66. +3,896 −0 lib/kirbybase.rb
  67. +4,004 −0 lib/kirbybase_kb_column_stuff.rb
  68. +17 −0 test/base_test.rb
  69. +80 −0 test/tc_local_db.rb
  70. +803 −0 test/tc_local_table.rb
  71. +4 −0 test/ts_local.rb
67 README
@@ -0,0 +1,67 @@
+= KirbyBase 2.6
+
+A small, plain-text, dbms written in Ruby. It can be used either embedded
+or client/server.
+
+
+== Installation
+
+Unpack the file you downloaded. Execute "ruby install.rb" or simply make
+sure kirbybase.rb is somewhere in your Ruby library path.
+
+
+== Documentation
+
+Documentation is in kirbybaserubymanual.html. Also, RDoc generated
+documentation is in the doc directory.
+
+See the examples directory for examples of how to use KirbyBase.
+
+
+== Manifest
+
+* README - this file
+* install.rb - install script
+* changes.txt - history of changes.
+* kirbybaserubymanual.html - documentation
+* lib/kirbybase.rb - dbms library
+* bin/kbserver.rb - multi-threaded database server script.
+* test directory - unit tests
+* examples directory - many example scripts demonstrating features.
+* images directory - images used in manual.
+
+
+== Author
+
+Written in 2005 by Jamey Cribbs <mailto:jcribbs@twmi.rr.com>
+
+
+== License
+
+KirbyBase is distributed under the same license as Ruby.
+
+Copyright (c) 2005 Jamey Cribbs
+
+
+
+== Warranty
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+
+== Feedback
+
+Please send any bug reports, suggestions, ideas,
+improvements, to:
+
+jcribbs@netpromi.com
+
+== Home Page
+
+http://www.netpromi.com/kirbybase_ruby.html
18 bin/kbserver.rb
@@ -0,0 +1,18 @@
+# Multi-user server script for KirbyBase.
+
+require 'kirbybase'
+require 'drb'
+
+host = ''
+port = 44444
+
+puts 'Initializing database server and indexes...'
+
+# Create an instance of the database.
+db = KirbyBase.new(:server)
+
+DRb.start_service('druby://:44444', db)
+
+puts 'Server ready to receive connections...'
+
+DRb.thread.join
144 changes.txt
@@ -0,0 +1,144 @@
+2006-06-27:: Version 2.6
+* Removed NilClass#method_missing. I have replaced it with a new class
+ called KBNilClass. Thanks to a host of people for help on this,
+ including: Assaph Mehr, James Edward Gray II, Matthew Desmarais,
+ Logan Capaldo, Trans, John Carter, Dave Burt and anyone else I missed.
+* Added conditional require logic so that KirbyBase will use FasterCVS if
+ it is available. Thanks to James Edward Gray II for this.
+* You can now delay index creation in local mode. Thanks to Nicholas Rahn
+ for this.
+* Added ability to allow for a custom record class with no kb_create or
+ kb_defaults methods. KirbyBase will return each result record as an
+ instance of the custom record class, and will attempt to set attributes
+ with the same names as the table's field names equal to the values of
+ the table record's fields. Thanks to Hal Fulton for this idea.
+
+2005-12-30:: Version 2.5.2
+* Changed the behavior of KBTable#insert method. If user specifies nil
+ for a field value and there is a default value for that field, the
+ default value will no longer override the user specified nil value.
+ Thanks to Assaph Mehr for suggesting this.
+
+2005-12-28:: Version 2.5.1
+* Fixed a bug that had broken encrypted tables.
+* Changed KBTable#pack method so that it raises an error if trying to
+ execute when :connect_type==:client.
+* Fixed a bug where it was possible to insert records missing a required
+ field if using a hash. Thanks to Adam Shelly for this.
+* Fixed a bug that occurred when you tried to update records using a
+ block and you tried to reference a field in the current record inside
+ the block. Much thanks to Assaph Mehr for reporting this.
+* Fixed a bug that allowed you to have duplicate column names. Thanks to
+ Assaph Mehr for spotting this.
+* Changed the way KBTable#set works with memo/blob fields.
+* Started creating unit tests.
+* Changed the KBTable#clear method to return number of records deleted.
+ Thanks to Assaph Mehr for this enhancement.
+* Moved #build_header_string from KBEngine class to KirbyBase class.
+* Added KirbyBase::VERSION constant.
+
+2005-12-01:: Version 2.5
+* Fixed a subtle bug in KBTable#create_indexes.
+* Added the following new methods to KBTable: add_index, drop_index,
+ rename_column, change_column_type, change_column_default_value, and
+ change_column_required.
+* Added the ability to specify a default column value at table creation
+ time.
+* Added the ability to specify, at table creation time, that a column value
+ is required when inserting or updating records.
+* Removed #add_table_column and #drop_table_column from KirbyBase class
+ and added #add_column and #drop_column to KBTable class. I felt like
+ it made more sense to have these methods in the table's class rather
+ than the database's class.
+* Added KirbyBase#rename_table method.
+* Added the ability to, upon database initialization, specify that index
+ creation should not happen until a table is actually opened. This
+ speeds up database initialization at the cost of slower table
+ initialization later.
+
+2005-11-13:: Version 2.4
+* Added a new column type: :Time. Thanks to George Moschovitis for coding
+ this enhancement.
+* Added more functionality to Memo and Blob fields. They are no longer
+ just read-only. You can now also write to them from KirbyBase. The
+ interface for Memo and Blob fields has changed because of this.
+* Added the ability to specify, when you initialize a database connection,
+ a base directory where memo/blob fields will be stored.
+* Changed the way indexes are handled by KBTable in client/server mode.
+ Now, when KBTable grabs an index from KBEngine, it will hold onto it and
+ re-use it unless it has been modified since the last time it grabbed it.
+ This speeds up subsequent queries on the same index.
+* Removed the restriction that the child table had to exist before you
+ could define a Link_many field in #create_table. I did this so that
+ it would possible to now define many-to-many links. See the example in
+ the distribution. This also goes for Lookup fields.
+* Added two sample scripts: kbserverctl.rb and kbserver_daemon.rb, that
+ show how to set up a KirbyBase server process as a Windows Service.
+ Thanks to Daniel Berger for his excellent package, win32-service.
+* Thouroughly revised the manual. I used the excellent text document
+ formatter, AsciiDoc. Many thanks to Stuart Rackham for developing this
+ great tool.
+* Fixed a bug in KBTable#clear that was causing the recno counter not to
+ be reset. Thanks to basi for this.
+
+2005-10-10:: Version 2.3
+* Added ability to specify lookup fields.
+* Added ability to specify one-to-many links between tables.
+* Added ability to specify calculated fields in tables.
+* Added Memo and Blob field types.
+* Added YAML field type. Many thanks to Logan Capaldo for this idea!
+* Added indexing to speed up queries.
+* Two new methods: #add_table_column and #drop_table_column.
+* Added the ability to designate a table field as the "key" field, for
+ Lookup purposes. This simply makes it easier to define Lookup fields.
+* Added "crosstab" capabilities to KBResultSet.
+
+2005-08-09:: Version 2.2.1
+* Fixed a bug in with_write_lock. Thanks to Zed A. Shaw for this bugfix.
+* Fixed a bug that occurred if @record_class was a nested class. Thanks
+ to Hal Fulton for this bugfix.
+
+2005-05-02:: Version 2.2
+* By far the biggest change in this version is that I have completely
+ redesigned the internal structure of the database code. Because the
+ KirbyBase and KBTable classes were too tightly coupled, I have created
+ a KBEngine class and moved all low-level I/O logic and locking logic
+ to this class. This allowed me to restructure the KirbyBase class to
+ remove all of the methods that should have been private, but couldn't be
+ because of the coupling to KBTable. In addition, it has allowed me to
+ take all of the low-level code that should not have been in the KBTable
+ class and put it where it belongs, as part of the underlying engine. I
+ feel that the design of KirbyBase is much cleaner now. No changes were
+ made to the class interfaces, so you should not have to change any of
+ your code.
+* Changed str_to_date and str_to_datetime to use Date#parse method.
+ Thanks to Emiel van de Laar for this enhancement.
+* Changed #pack method so that it no longer reads the whole file into
+ memory while packing it.
+ Thanks to Hugh Sasse for reporting this bug.
+* Changed code so that special character sequences like &linefeed; can be
+ part of input data and KirbyBase will not interpret it as special
+ characters.
+ Thanks to Hugh Sasse for this bug fix.
+
+2005-04-11:: Version 2.1
+* Changed the interface to KirbyBase#new and KirbyBase#create_table. You
+ now specify arguments via a code block or as part of the argument list.
+* Added the ability to specify a class at table creation time.
+ Thereafter, whenever you do a #select, the result set will be an array
+ of instances of that class, instead of instances of Struct. You can
+ also use instances of this class as the argument to #insert, #update,
+ #set.
+* Added the ability to encrypt a table so that it is no longer stored as
+ a plain-text file.
+* Added the ability to explicity specify that you want a result set to be
+ sorted in ascending order.
+* Added the ability to import a csv file into an existing table.
+* Added the ability to select a record as if the table were a Hash with
+ it's key being the recno field.
+* Added the ability to update a record as if the table were a Hash with
+ it's key being the recno field.
+
+2005-03-28:: Version 2.0
+* New version with completely new interface. A huge thanks to Hal Fulton
+ for all of his help with this new version.
237 examples/aaa_try_this_first/kbtest.rb
@@ -0,0 +1,237 @@
+#Simple test of KirbyBase.
+
+require 'kirbybase'
+require 'date'
+
+def print_divider(text)
+ puts
+ puts text.center(75, '-')
+ puts
+end
+
+#-------------------- Initialize KirbyBase Instance ------------------------
+# To run local, single-user, uncomment next line.
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+#----------------------- Drop Table Example --------------------------------
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+#----------------------- Create Table Example ------------------------------
+# Create a table.
+plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
+ :role, :String, :speed, :Integer, :range, :Integer, :began_service, :Date,
+ :still_flying, :Boolean) { |obj| obj.encrypt = false }
+
+#----------------------- Insert Record Examples ----------------------------
+# Four different ways to insert records in KirbyBase.
+
+# 1) Insert a record using an array for the input values.
+plane_tbl.insert('FW-190', 'Germany', 'Fighter', 399, 499,
+ Date.new(1942,12,1), false)
+
+# 2) Insert a record using a hash for the input values.
+plane_tbl.insert(:name => 'P-51', :country => 'USA',
+ :role => 'Fighter', :speed => 403, :range => 1201,
+ :began_service => Date.new(1943,6,24), :still_flying => true)
+
+# 3) Insert a record using a Struct for the input values.
+InputRec = Struct.new(:name, :country, :role, :speed, :range,
+ :began_service, :still_flying)
+rec = InputRec.new('P-47', 'USA', 'Fighter', 365, 888, Date.new(1943,3,12),
+ false)
+plane_tbl.insert(rec)
+
+# 4) Insert a record using a code block for the input values.
+plane_tbl.insert { |r|
+ r.name = 'B-17'
+ r.country = 'USA'
+ r.role = 'Bomber'
+ r.speed = 315
+ r.range = r.speed * 3
+ r.began_service = Date.new(1937, 5, 1)
+ r.still_flying = true
+}
+
+# If a table is already existing and you need to get a reference to it so
+# that you can insert, select, etc., just do a get_table.
+plane_tbl_another_reference = db.get_table(:plane)
+
+# Then, you can use it just like you have been using the reference you got
+# when you created the table.
+plane_tbl_another_reference.insert('Typhoon', 'Great Britain',
+ 'Fighter-Bomber', 389, 690, Date.new(1944,11,20), false)
+
+# Insert a bunch more records so we can have some "select" fun below.
+plane_tbl.insert('Spitfire', 'Great Britain', 'Fighter', 345, 540,
+ Date.new(1939,2,18), true)
+plane_tbl.insert('Oscar', 'Japan', 'Fighter', 361, 777,
+ Date.new(1943,12,31), false)
+plane_tbl.insert('ME-109', 'Germany', 'Fighter', 366, 514,
+ Date.new(1936,7,7),true)
+plane_tbl.insert('JU-88', 'Germany', 'Bomber', 289, 999,
+ Date.new(1937,1,19), false)
+plane_tbl.insert('P-39', 'USA', 'Fighter', nil, nil,
+ nil, false)
+plane_tbl.insert('Zero', 'Japan', 'Fighter', 377, 912,
+ Date.new(1937,5,15), true)
+plane_tbl.insert('B-25', 'USA', '', 320, 1340, Date.new(1940,4,4), true)
+
+#--------------------- Update Examples -------------------------------------
+# Four different ways to update existing data in KirbyBase. In all three
+# instances, you still need a code block attached to the update method in
+# order to select records that will be updated.
+
+# 1) Update record using a Hash, Struct, or an Array.
+plane_tbl.update(:speed => 405, :range => 1210) { |r| r.name == 'P-51' }
+
+# 2) Update record using a Hash, Struct, or an Array, via the set
+# command.
+plane_tbl.update {|r| r.name == 'P-51'}.set(:speed => 405, :range => 1210)
+
+# 3) Update record by treating table as if it were a Hash and the keys were
+# recno's.
+plane_tbl[2] = {:speed => 405, :range => 1210}
+
+# 4) Update record using a code block, via the set command. Notice how you
+# have access to the current record's values within the block.
+plane_tbl.update {|r| r.name == 'P-51'}.set {|r|
+ r.speed = r.speed+7
+ r.range = r.range-2
+}
+
+#--------------------- Delete Examples -------------------------------------
+# Delete 'FW-190' record.
+plane_tbl.delete { |r| r.name == 'FW-190' }
+
+#---------------------- Select Example 0 -----------------------------------
+print_divider('Select Example 0')
+# Select all records, including all fields in result set.
+plane_tbl.select.each { |r|
+ puts(('%s ' * r.members.size) % r.to_a)
+}
+
+#-------------------------- Select Example 1 -------------------------------
+print_divider('Select Example 1')
+# Select all Japanese planes. Include just name and speed in the result.
+plane_tbl.select(:name, :speed) { |r| r.country == 'Japan' }.each { |r|
+ puts '%s %s' % [r.name, r.speed]
+}
+
+#-------------------------- Select Example 2 -------------------------------
+print_divider('Select Example 2')
+# Select all US planes with a speed greater than 350mph. Include just name
+# and speed in result set.
+plane_tbl.select(:name, :speed) { |r|
+ r.country == 'USA' and r.speed > 350
+}.each { |r| puts '%s %s' % [r.name, r.speed] }
+
+#-------------------------- Select Example 3 -------------------------------
+print_divider('Select Example 3')
+# Select all Axis fighters.
+plane_tbl.select { |r|
+ (r.country == 'Germany' or r.country == 'Japan') and r.role == 'Fighter'
+}.each { |r| puts r }
+
+#-------------------------- Select Example 4 -------------------------------
+print_divider('Select Example 4')
+# Same query as above, but let's use regular expressions instead of an 'or'.
+plane_tbl.select { |r|
+ r.country =~ /Germany|Japan/ and r.role == 'Fighter'
+}.each { |r| puts r }
+
+#-------------------------- Select Example 5 -------------------------------
+print_divider('Select Example 5')
+# Select all Bombers (but not Fighter-Bombers) and return only their name
+# and country. This is also an example of how to get a reference to an
+# existing table as opposed to already having a reference to one via the
+# table_create method.
+match_role = /^Bomber/
+plane_tbl2 = db.get_table(:plane)
+plane_tbl2.select(:name, :country) { |r| r.role =~ match_role }.each { |r|
+ puts '%s %s' % r.to_a
+}
+
+#-------------------------- Select Example 6 -------------------------------
+print_divider('Select Example 6')
+# Select all planes. Include just name, country, and speed in result set.
+# Sort result set by country (ascending) then name (ascending).
+plane_tbl.select(:name, :country, :speed).sort(:country,
+ :name).each { |r| puts "%s %s %d" % r.to_a }
+
+#-------------------------- Select Example 7 -------------------------------
+print_divider('Select Example 7')
+# Select all planes. Include just name, country, and speed in result set.
+# Return result set as a nicely formatted report, sorted by
+# country (ascending) then speed (descending).
+puts plane_tbl.select(:name, :country, :speed).sort(+:country,
+ -:speed).to_report
+
+#-------------------------- Select Example 8 -------------------------------
+print_divider('Select Example 8')
+# Select planes that are included in nameArray.
+nameArray = ['P-51', 'Spitfire', 'Zero']
+plane_tbl.select { |r| nameArray.include?(r.name) }.each { |r| puts r }
+
+#-------------------------- Select Example 9 -------------------------------
+print_divider('Select Example 9')
+# You can select a record as if the table is a hash and it's keys are the
+# recno's.
+# Select the record that has a recno of 5.
+puts plane_tbl[5].name
+
+#-------------------------- Select Example 10 -------------------------------
+print_divider('Select Example 10')
+# You can even have a select within the code block of another select. Here
+# we are selecting all records that are from the same country as the Zero.
+puts plane_tbl.select { |r|
+ r.country == plane_tbl.select { |x| x.name == 'Zero' }.first.country
+}
+
+#-------------------------- Select Example 11 -------------------------------
+print_divider('Select Example 11')
+# Select all planes.
+plane_tbl.select.each { |r| puts r }
+
+#-------------------------- Select Example 12 -------------------------------
+print_divider('Select Example 12')
+# Select all planes with a speed of nil.
+
+#**************** Note: This example also demonstrates the change from
+# nil to kb_nil for KirbyBase's internal representation of a nil value. You
+# should only encounter this different if you have to check for nil in your
+# query, as this example does. Other than that, everything else should
+# be transparent, since KirbyBase converts a kb_nil back into a nil when it
+# returns a query's result set.
+#***************
+plane_tbl.select { |r| r.speed.kb_nil? }.each { |r| puts r }
+
+#-------------------------- Select Example 13 -------------------------------
+print_divider('Select Example 13')
+# Same thing, but in a slightly different way.
+
+#**************** Note: This example also demonstrates the change from
+# nil to kb_nil for KirbyBase's internal representation of a nil value. You
+# should only encounter this different if you have to check for nil in your
+# query, as this example does. Other than that, everything else should
+# be transparent, since KirbyBase converts a kb_nil back into a nil when it
+# returns a query's result set.
+#***************
+plane_tbl.select { |r| r.speed == kb_nil }.each { |r| puts r }
+
+#-------------------------- Misc. Methods Examples -------------------------
+print_divider('Misc. Methods Examples')
+puts 'Total # of records in table: %d' % plane_tbl.total_recs
+puts
+puts 'Fields for plane.tbl:'
+plane_tbl.field_names.zip(plane_tbl.field_types).each { |r|
+ print r[0].to_s.ljust(15), r[1].to_s, "\n"
+}
27 examples/add_column_test/add_column_test.rb
@@ -0,0 +1,27 @@
+#Test of add_column method.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+# Create a table.
+plane_tbl = db.create_table(:plane, :name, :String, :speed, :Integer,
+ :service_date, :Date, :still_flying, :Boolean)
+
+# Insert a bunch more records so we can have some "select" fun below.
+plane_tbl.insert('Spitfire', 345, Date.new(1939,2,18), true)
+plane_tbl.insert('Oscar', 361, Date.new(1943,12,31), false)
+plane_tbl.insert('ME-109', 366, Date.new(1936,7,7),true)
+plane_tbl.insert('JU-88', 289, Date.new(1937,1,19), false)
+plane_tbl.insert('P-39', nil, nil, false)
+plane_tbl.insert('Zero', 377, Date.new(1937,5,15), true)
+
+plane_tbl.add_column(:range, {:DataType=>:Integer, :Index=>1}, :speed)
+
+plane_tbl.update { |r| r.name == 'Spitfire' }.set(:range => 454)
+
+puts plane_tbl.select_by_range_index { |r| r.range > 400 }.sort(:recno
+ ).to_report
51 examples/calculated_field_test/calculated_field_test.rb
@@ -0,0 +1,51 @@
+# This example script shows how to specify calculated fields in a KirbyBase
+# table. Calculated fields are "virtual" fields. They do not really exist
+# in the table, but are calculated during a select query. However, once
+# calculated, they behave just like "real" table fields.
+
+# In this example, we will create an expenses table that holds information
+# on recent purchases. The total_cost field is a calculated field. We tell
+# KirbyBase how to calculate it's value, i.e. by multiplying the quantity
+# field by the price field.
+
+require 'kirbybase'
+require 'date'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If table exists, delete it.
+db.drop_table(:expenses) if db.table_exists?(:expenses)
+
+# Create a table.
+expenses_tbl = db.create_table(:expenses,
+ :transaction_date, :Date,
+ :description, :String,
+ :quantity, :Integer,
+ :price, :Float,
+ :total_cost, {:DataType=>:Float, :Calculated=>'quantity * price'}
+)
+
+# Insert a couple of expense records.
+expenses_tbl.insert({:transaction_date => Date.new(2005, 9, 7),
+ :description => 'Pencils', :quantity => 100, :price => 0.50})
+expenses_tbl.insert({:transaction_date => Date.new(2005, 9, 8),
+ :description => 'Books', :quantity => 3, :price => 45.0})
+
+# Select all records and send the result to the screen in report format.
+# Notice how the total_cost field for each record has been calculated for
+# you by multiplying price times quantity.
+puts "\nSelect all records:\n\n"
+puts expenses_tbl.select.to_report
+
+# And, you can even use a calculated field in your select condition. Here
+# we are only selecting records whose total cost is greater than $100.
+puts "\n\nSelect only records with a total cost greater than $100:\n\n"
+puts expenses_tbl.select { |r| r.total_cost > 100.00 }.to_report
25 examples/change_column_type_test/change_column_type_test.rb
@@ -0,0 +1,25 @@
+# This script is an example of how to change a column type.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:log) if db.table_exists?(:log)
+
+log_tbl = db.create_table(:log, :log_timestamp, :DateTime, :msg, :String)
+
+log_tbl.insert(DateTime.now, 'This is a log message')
+log_tbl.insert(DateTime.now, 'This is a another log message')
+log_tbl.insert(DateTime.now, 'This is the final log message')
+
+p log_tbl.select
+puts;puts
+
+log_tbl.change_column_type(:log_timestamp, :String)
+
+p log_tbl.select
+puts;puts
+
+p log_tbl.field_types
+
44 examples/column_required_test/column_required_test.rb
@@ -0,0 +1,44 @@
+# This script is an example of how to specify that a value is required for a
+# column.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+
+# Create a table. Notice how we specify a default value for :category.
+address_book_tbl = db.create_table(:address_book,
+ :firstname, :String, :lastname, :String, :street_address, :String,
+ :city, :String, :phone, :String,
+ :category, {:DataType=>:String, :Required=>true})
+
+begin
+ # Insert a record. Notice that I am passing nil for :category. This
+ # will cause KirbyBase to raise an exception.
+ address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave',
+ 'Gotham City', '111-111-1111', nil)
+rescue StandardError => e
+ puts e
+ puts;puts
+end
+
+begin
+ # Same thing should happen if I don't even specify a value for
+ # :category.
+ address_book_tbl.insert(:firstname=>'Bruce', :lastname=>'Wayne',
+ :street_addres=>'1234 Bat Cave', :city=>'Gotham City',
+ :phone=>'111-111-1111')
+rescue StandardError => e
+ puts e
+ puts;puts
+end
+
+# Now, let's turn off the required flag for :category.
+address_book_tbl.change_column_required(:category, false)
+
+# And we will attempt to add the record again.
+address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave',
+ 'Gotham City', '111-111-1111', nil)
+
100 examples/crosstab_test/crosstab_test.rb
@@ -0,0 +1,100 @@
+# This script demonstrates how to use crosstab functionality of a
+# KirbyBase result set. A KirbyBase result set automatically has an
+# equivalent transposed array whereby all of the values of a column are
+# available. I call this a crosstab, but I am probably using this term
+# incorrectly. Perhaps the examples below will help explain what I am
+# talking about.
+
+# In this example, we have an order table and an order_item table. Each
+# record in the order table represents a customer order. The order_item
+# table holds the detail items for each order. We create a one-to-many link
+# between the order table and the order_item table by providing extra
+# information about the order.items field when we create the order table.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If tables exists, delete it.
+db.drop_table(:order) if db.table_exists?(:order)
+db.drop_table(:order_item) if db.table_exists?(:order_item)
+
+# Create an order item table. This is the child table to the order table.
+# Make sure you create the child table BEFORE you create the parent table
+# so that KirbyBase can take advantage of any indexes that you have defined.
+order_item_tbl = db.create_table(:order_item,
+ :item_id, :Integer,
+ :order_id, :Integer,
+ :descr, :String,
+ :qty, :Integer,
+ :price, :Float,
+ :total, {:DataType=>:Float, :Calculated=>'qty*price'}
+)
+
+# Create an order table. We are telling KirbyBase that the items field is
+# to be linked to the order_item table by comparing the order.order_id
+# field to the order_item.order_id field. By specifying :Link_many, we are
+# telling KirbyBase to make this a one-to-many link. The result of this is
+# that when you do a select, the items field of the order table is going to
+# hold a reference to a ResultSet (i.e. Array) holding all order_item
+# records whose order_id field match the order_id field in the order record.
+order_tbl = db.create_table(:order,
+ :order_id, :Integer,
+ :customer, :String,
+ :items, {:DataType=> :ResultSet, :Link_many=> [:order_id, :order_item,
+ :order_id]}
+)
+
+# Insert some order records.
+order_tbl.insert({:order_id=>345, :customer=>'Ford'})
+order_tbl.insert({:order_id=>454, :customer=>'Microsoft'})
+order_tbl.insert({:order_id=>17, :customer=>'Boeing'})
+
+# Insert some order item records.
+order_item_tbl.insert(1,345,'Steel',30,19.99,nil)
+order_item_tbl.insert(2,345,'Glass',5,4.15,nil)
+order_item_tbl.insert(5,454,'Floppies',750000,0.5,nil)
+order_item_tbl.insert(3,17,'Wheels',200,2500.0,nil)
+order_item_tbl.insert(4,17,'Wings',25,1000000.0,nil)
+
+
+# Print all orders. Under each order print all items in that order. Notice
+# that we are able to print the total for each order because we have access
+# to the entire order_items.total column of the result set. We don't have
+# to loop through all of the order item result set records to add up the
+# total for each order.
+puts "\nPrint all orders:\n"
+order_tbl.select.each do |r|
+ puts "\nid: %3d customer: %-10s total charge: %11.2f" % [r.order_id,
+ r.customer, r.items.total.inject { |sum, n| sum + n }]
+
+ r.items.each do |i|
+ puts "\titem: %-10s %6d * %10.2f = %11.2f" % [i.descr,
+ i.qty, i.price, i.total]
+ end
+end
+puts '-' * 70;puts
+
+# You can even use the ability to access an entire column of values in your
+# select statements. In this example, we only want to select those orders
+# whose total charges exceeds $100,000. We can do this because we have
+# access to the entire total column of the child table, order items.
+puts "Print only orders whose total charge exceeds $100,000:\n"
+order_tbl.select { |r| r.items.total.inject { |sum, n| sum+n } > 100000
+ }.each do |r|
+ puts "\nid: %3d customer: %-10s total charge: %11.2f" % [r.order_id,
+ r.customer, r.items.total.inject { |sum, n| sum + n }]
+
+ r.items.each do |i|
+ puts "\titem: %-10s %6d * %10.2f = %11.2f" % [i.descr,
+ i.qty, i.price, i.total]
+ end
+end
31 examples/csv_import_test/csv_import_test.rb
@@ -0,0 +1,31 @@
+#Test of CSV file import.
+
+require 'kirbybase'
+require 'date'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+# Create a table.
+plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
+ :role, :String, :speed, :Integer, :range, :Integer, :began_service, :Date,
+ :still_flying, :Boolean)
+
+# Import csv file.
+puts 'Records imported: %d' % plane_tbl.import_csv('plane.csv')
+
+puts
+
+# Now, lets show that the csv file did, in fact, get imported.
+puts plane_tbl.select(:name, :country, :role, :speed, :range).sort(:name
+ ).to_report
11 examples/csv_import_test/plane.csv
@@ -0,0 +1,11 @@
+FW-190,Germany,Fighter,399,499,1942-12-01,false
+P-51,USA,Fighter,405,1210,1943-06-24,true
+P-47,USA,Fighter,365,888,1943-03-12,false
+B-17,USA,Bomber,315,1400,1937-05-01,true
+Typhoon,Great Britain,Fighter-Bomber,389,690,1944-11-20,false
+Spitfire,Great Britain,Fighter,345,540,1939-02-18,true
+Oscar,Japan,Fighter,361,777,1943-12-31,false
+ME-109,Germany,Fighter,366,514,1936-07-07,true
+JU-88,Germany,Bomber,289,999,1937-01-19,false
+P-39,USA,Fighter,,,,false
+Zero,Japan,Fighter,377,912,1937-05-15,true
54 examples/default_value_test/default_value_test.rb
@@ -0,0 +1,54 @@
+# This script is an example of how to specify a default value for a column.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+
+# Create a table. Notice how we specify a default value for :category.
+address_book_tbl = db.create_table(:address_book,
+ :firstname, :String, :lastname, :String, :street_address, :String,
+ :city, :String, :phone, :String,
+ :category, {:DataType=>:String, :Default=>'Super Hero'})
+
+# Insert a record. Notice that I am not passing a value for :category.
+# KirbyBase will insert the default value, 'Super Hero', in that field.
+address_book_tbl.insert(:firstname=>'Bruce', :lastname=>'Wayne',
+ :street_address=>'1234 Bat Cave', :city=>'Gotham City',
+ :phone=>'111-111-1111')
+
+# Insert another record. Here we supply the value for :category, so
+# KirbyBase will use it instead of the default.
+address_book_tbl.insert(:firstname=>'Bugs', :lastname=>'Bunny',
+ :street_address=>'1234 Rabbit Hole', :city=>'The Forest',
+ :phone=>'222-222-2222', :category=>'Cartoon Character')
+
+# Insert another record. Here we explicitly supply nil as the value for
+# category. KirbyBase will not override this with the default value
+# because we explicitly specified nil as the value.
+address_book_tbl.insert(:firstname=>'Super', :lastname=>'Man',
+ :street_address=>'1234 Fortress of Solitude', :city=>'Metropolis',
+ :phone=>'333-333-3333', :category=>nil)
+
+# Now lets change the default value for :category to 'President'.
+address_book_tbl.change_column_default_value(:category, 'President')
+
+# And let's add another record without supplying a value for :category.
+address_book_tbl.insert(:firstname=>'George', :lastname=>'Bush',
+ :street_address=>'1600 Pennsylvania Ave', :city=>'Washington',
+ :phone=>'333-333-3333')
+
+# Now, let's remove the default value for :category
+address_book_tbl.change_column_default_value(:category, nil)
+
+# And add another record. We won't specify a value for :category and,
+# KirbyBase will not use a default value, because we removed it.
+address_book_tbl.insert(:firstname=>'Silver', :lastname=>'Surfer',
+ :street_address=>'1234 Galaxy Way', :city=>'Any City',
+ :phone=>'444-444-4444')
+
+# Now lets print the table out and you will see how all of the defaults
+# worked.
+puts address_book_tbl.select.to_report
24 examples/drop_column_test/drop_column_test.rb
@@ -0,0 +1,24 @@
+#Test of drop_column method.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+# Create a table.
+plane_tbl = db.create_table(:plane, :name, :String, :speed, :Integer,
+ :service_date, :Date, :still_flying, :Boolean)
+
+# Insert a bunch more records so we can have some "select" fun below.
+plane_tbl.insert('Spitfire', 345, Date.new(1939,2,18), true)
+plane_tbl.insert('Oscar', 361, Date.new(1943,12,31), false)
+plane_tbl.insert('ME-109', 366, Date.new(1936,7,7),true)
+plane_tbl.insert('JU-88', 289, Date.new(1937,1,19), false)
+plane_tbl.insert('P-39', nil, nil, false)
+plane_tbl.insert('Zero', 377, Date.new(1937,5,15), true)
+
+plane_tbl.drop_column(:speed)
+
+puts plane_tbl.select.to_report
46 examples/indexes_test/add_index_test.rb
@@ -0,0 +1,46 @@
+# This script is an example of how to add an index to an existing table.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+
+address_book_tbl = db.create_table(:address_book,
+ :firstname, :String, :lastname, :String, :street_address, :String,
+ :city, :String, :phone, :String, :category, :String)
+
+# Insert some contact info records.
+address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
+ '111-111-1111', 'Super Hero')
+address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
+ '222-222-2222', 'Cartoon Character')
+address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
+ 'Washington', '333-333-3333', 'President')
+address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
+ 'Any City', '444-444-4444', 'Super Hero')
+
+# Select all super heros without using the index.
+address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+
+address_book_tbl.add_index(:category)
+
+# Now, do the same query, but use the category index. These
+# select_by_index methods are automatically created by KirbyBase when you
+# specify that a column be indexed.
+address_book_tbl.select_by_category_index { |r|
+ r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+
+address_book_tbl.add_index(:firstname, :lastname)
+
+# Select Bugs Bunny using the firstname+lastname index.
+address_book_tbl.select_by_firstname_lastname_index { |r|
+ r.firstname == 'Bugs' and r.lastname == 'Bunny'
+}.each { |r| puts '%s %s %s' % [r.firstname, r.lastname, r.phone] }
66 examples/indexes_test/drop_index_test.rb
@@ -0,0 +1,66 @@
+# This script is an example of how to drop an index from an existing table.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+
+address_book_tbl = db.create_table(:address_book,
+ :firstname, {:DataType=>:String, :Index=>1},
+ :lastname, {:DataType=>:String, :Index=>1},
+ :street_address, :String,
+ :city, :String,
+ :phone, :String,
+ :category, {:DataType=>:String, :Index=>2}
+)
+
+# Insert some contact info records.
+address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
+ '111-111-1111', 'Super Hero')
+address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
+ '222-222-2222', 'Cartoon Character')
+address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
+ 'Washington', '333-333-3333', 'President')
+address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
+ 'Any City', '444-444-4444', 'Super Hero')
+
+p address_book_tbl.field_indexes
+puts;puts
+
+address_book_tbl.select_by_category_index { |r|
+ r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+
+address_book_tbl.drop_index(:category)
+
+begin
+ address_book_tbl.select_by_category_index { |r|
+ r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+ }
+rescue StandardError => e
+ puts e
+ puts;puts
+end
+
+# Select Bugs Bunny using the firstname+lastname index.
+address_book_tbl.select_by_firstname_lastname_index { |r|
+ r.firstname == 'Bugs' and r.lastname == 'Bunny'
+}.each { |r| puts '%s %s %s' % [r.firstname, r.lastname, r.phone] }
+
+address_book_tbl.drop_index(:firstname, :lastname)
+
+begin
+ address_book_tbl.select_by_firstname_lastname_index { |r|
+ r.firstname == 'Bugs' and r.lastname == 'Bunny'
+ }.each { |r| puts '%s %s %s' % [r.firstname, r.lastname, r.phone] }
+rescue StandardError => e
+ puts e
+ puts;puts
+end
+
+p address_book_tbl.field_indexes
94 examples/indexes_test/index_test.rb
@@ -0,0 +1,94 @@
+# This script is an example of how to use indexes in KirbyBase. Indexes
+# allow for faster queries on large datasets.
+#
+# To use indexes, you must first specify which fields are to be indexed.
+# You do this at table creation time. Both single and compound indexes can
+# be created. Then, when performing a select query, you simply use the
+# automatically created select_by_?????_index method, where ????? is
+# replaced by the name(s) of the indexed field(s). That's it. Everything
+# else concerning building and maintaing indexes is done by KirbyBase.
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If table exists, delete it.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+
+# Here we are creating a table to hold contact info. We are going to create
+# two indexes. One index is going to be a compound index containing the
+# firstname and lastname fields. Notice how we group the firstname and
+# lastname fields into one index by specifying :Index=>1 for both of them.
+# This just tells KirbyBase that the two fields should be combined into one
+# compound index because they both are using the same index number. The
+# second index is going to be a single index containing the category field.
+# Since we want it to be a separate index, we simply use the next available
+# number, 2, as the value of it's :Index key.
+address_book_tbl = db.create_table(:address_book,
+ :firstname, {:DataType=>:String, :Index=>1},
+ :lastname, {:DataType=>:String, :Index=>1},
+ :street_address, :String,
+ :city, :String,
+ :phone, :String,
+ :category, {:DataType=>:String, :Index=>2},
+ :age, {:DataType=>:Integer, :Index=>3}
+)
+
+# Insert some contact info records.
+address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
+ '111-111-1111', 'Super Hero', 39)
+address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
+ '222-222-2222', 'Cartoon Character', 12)
+address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
+ 'Washington', '333-333-3333', 'President', 2)
+address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
+ 'Any City', '444-444-4444', 'Super Hero', 199)
+address_book_tbl.insert('John', 'Doe', '1234 Robin Lane', 'Detroit',
+ '999-999-9999', nil, 54)
+address_book_tbl.insert(nil, 'NoFirstName', 'Nowhere Road', 'Notown',
+ '000-000-0000', 'Nothing', nil)
+
+# Select all super heros without using the index.
+address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+# Now, do the same query, but use the category index. These
+# select_by_index methods are automatically created by KirbyBase, based on
+# the indexes you specified at table creation.
+address_book_tbl.select_by_category_index { |r|
+ r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+# Select Bugs Bunny using the firstname+lastname index.
+address_book_tbl.select_by_firstname_lastname_index { |r|
+ r.firstname == 'Bugs' and r.lastname == 'Bunny'
+}.each { |r| puts '%s %s %s' % [r.firstname, r.lastname, r.phone] }
+
+puts;puts
+# Select the guy with no first name using the firstname+lastname index.
+address_book_tbl.select_by_firstname_lastname_index { |r|
+ r.lastname == 'NoFirstName'
+}.each { |r| puts '%s %s %s' % [r.firstname, r.lastname, r.phone] }
+
+puts;puts
+# Select the guy with no first name using the firstname+lastname index.
+# This time we will explicitly say firstname should be nil
+address_book_tbl.select_by_firstname_lastname_index { |r|
+ r.firstname.nil? and r.lastname == 'NoFirstName'
+}.each { |r| puts '%s %s %s' % [r.firstname, r.lastname, r.phone] }
+
+puts;puts
+address_book_tbl.select_by_age_index { |r| r.age > 30 }.each { |r|
+ puts '%s %s %d' % [r.firstname, r.lastname, r.age] }
+
+puts;puts
+p address_book_tbl.field_indexes
47 examples/kbserver_as_win32_service/kbserver_daemon.rb
@@ -0,0 +1,47 @@
+# Modified version of kbserver.rb for use as Windows Service.
+
+require 'kirbybase'
+require 'drb'
+require 'win32/service'
+include Win32
+
+OPTIONS = {}
+
+class KBServerDaemon < Daemon
+ def initialize
+ # NOTE: Change this line to reflect where you want the log file to
+ # reside.
+ @log = 'C:\logs\db_server_log.txt'
+ begin
+ # NOTE: Change this line to reflect where the database tables
+ # are located.
+ @db = KirbyBase.new do |x|
+ x.connect_type = :server
+ x.path = 'C:\data'
+ end
+ rescue Exception => e
+ File.open(@log, "a+") { |fh| ft.puts "Error: #{e}" }
+ service_stop
+ end
+ end
+
+ def service_main
+ begin
+ # NOTE: Change this line to reflect what port you want to
+ # listen on.
+ DRb.start_service('druby://:44444', @db)
+ DRb.thread.join
+ rescue StandardError, InterrupError => e
+ File.open(@log, "a+") { |fh| fh.puts "Error: #{e}" }
+ service_stop
+ end
+ end
+
+ def service_stop
+ DRb.stop_service
+ exit
+ end
+end
+
+d = KBServerDaemon.new
+d.mainloop
75 examples/kbserver_as_win32_service/kbserverctl.rb
@@ -0,0 +1,75 @@
+# Control script for the KBServer service.
+
+require 'optparse'
+require 'win32/service'
+include Win32
+
+# You will want to change these values.
+kbserver_home = 'C:\kbserver'
+kbserver_prog = kbserver_home + '\kbserver_daemon.rb'
+kbserver_svc = 'KirbyBaseServerSvc'
+kbserver_name = 'KirbyBase Database Server'
+
+OPTIONS = {}
+
+ARGV.options do |opts|
+ opts.on("-d", "--delete", "Delete the service") {
+ OPTIONS[:delete] = true }
+ opts.on("-s", "--start", "Start the service") {
+ OPTIONS[:start] = true }
+ opts.on("-x", "--stop", "Stop the service") {
+ OPTIONS[:stop] = true }
+ opts.on("-i", "--install", "Install the service") {
+ OPTIONS[:install] = true }
+ opts.on("-h", "--help", "Show this help message") {
+ puts opts; exit }
+ opts.parse!
+end
+
+# Install the service.
+if OPTIONS[:install]
+ svc = Service.new
+ svc.create_service do |s|
+ s.service_name = kbserver_svc
+ s.display_name = kbserver_name
+ s.binary_path_name = 'c:\ruby\bin\ruby.exe ' + kbserver_prog
+ # This is required for now - bug in win32-service
+ s.dependencies = []
+ end
+ svc.close
+ puts "KirbyBase Server service installed"
+end
+
+# Start the service.
+if OPTIONS[:start]
+ Service.start(kbserver_svc)
+ started = false
+ while started == false
+ s = Service.status(kbserver_svc)
+ started = true if s.current_state == "running"
+ break if started == true
+ puts "One moment, " + s.current_state
+ sleep 1
+ end
+ puts "KirbyBase Server service started"
+end
+
+# Stop the service.
+if OPTIONS[:stop]
+ begin
+ Service.stop(kbserver_svc)
+ rescue
+ end
+ puts "KirbyBase Server service stopped"
+end
+
+# Delete the service. Stop it first.
+if OPTIONS[:delete]
+ begin
+ Service.stop(kbserver_svc)
+ rescue
+ end
+ Service.delete(kbserver_svc)
+ puts "KirbyBase Server service deleted"
+end
+
70 examples/link_many_test/link_many_test.rb
@@ -0,0 +1,70 @@
+# This script demonstrates how to link a field in the table to a subset
+# of records from another table (i.e. a "one to many" link in database
+# lingo).
+
+# In this example, we have an order table and an order_item table. Each
+# record in the order table represents a customer order. The order_item
+# table holds the detail items for each order. We create a one-to-many link
+# between the order table and the order_item table by providing extra
+# information about the order.items field when we create the order table.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If table exists, delete it.
+db.drop_table(:order) if db.table_exists?(:order)
+db.drop_table(:order_item) if db.table_exists?(:order_item)
+
+# Create an order item table. This is the child table to the order table.
+# Create child table before creating parent table so that KirbyBase can
+# take advantage of any indexes.
+order_item_tbl = db.create_table(:order_item,
+ :item_id, :Integer,
+ :order_id, :Integer,
+ :descr, :String,
+ :qty, :Integer,
+ :price, :Float
+)
+
+# Create a table. We are telling KirbyBase that the items field is
+# to be linked to the order_item table by comparing the order.order_id
+# field to the order_item.order_id field. By specifying :Link_many, we are
+# telling KirbyBase to make this a one-to-many link. The result of this is
+# that when you do a select, the items field of the order table is going to
+# hold a reference to a ResultSet (i.e. Array) holding all order_item
+# records whose order_id field match the order_id field in the order record.
+order_tbl = db.create_table(:order,
+ :order_id, :Integer,
+ :customer, :String,
+ :items, {:DataType=> :ResultSet, :Link_many=> [:order_id, :order_item,
+ :order_id]}
+)
+
+# Insert some order records.
+order_tbl.insert({:order_id=>345, :customer=>'Ford'})
+order_tbl.insert({:order_id=>454, :customer=>'Microsoft'})
+order_tbl.insert({:order_id=>17, :customer=>'Boeing'})
+
+# Insert some order item records.
+order_item_tbl.insert(1,345,'Steel',30,19.99)
+order_item_tbl.insert(2,345,'Glass',5,4.15)
+order_item_tbl.insert(5,454,'Floppies',750000,0.5)
+order_item_tbl.insert(3,17,'Wheels',200,2500.0)
+order_item_tbl.insert(4,17,'Wings',25,1000000.0)
+
+# Print all orders. Under each order print all items in that order.
+order_tbl.select.each do |r|
+ puts '%3d %s' % [r.order_id, r.customer]
+ r.items.each { |i|
+ puts "\t%d %15s %6d %10.2f" % [i.item_id, i.descr, i.qty, i.price]
+ }
+end
55 examples/lookup_field_test/lookup_field_test.rb
@@ -0,0 +1,55 @@
+# This script demonstrates how to link a field in the table to an entire
+# record from another table (i.e. a "one to one" relationship in database
+# lingo).
+
+# In the example below, we have a department table. For each department
+# record, the manager field is actually a reference to a record from the
+# person table. This allows us to reference the linked person record
+# through the manager field.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If tables exists, delete them.
+db.drop_table(:department) if db.table_exists?(:department)
+db.drop_table(:person) if db.table_exists?(:person)
+
+# Create a person table. Create lookup table first before the table that
+# uses the lookup table, so that KirbyBase can take advantage of any
+# indexes.
+person_tbl = db.create_table(:person,
+ :person_id, :String,
+ :name, :String,
+ :phone, :String
+)
+
+# Insert some person records.
+person_tbl.insert('000-13-5031', 'John Smith', '512.555.1234')
+person_tbl.insert('010-10-9999', 'Jane Doe', '313.724.4230')
+
+# Create a table. We are telling KirbyBase that the manager field is
+# to be linked to the person table.
+department_tbl = db.create_table(:department,
+ :dept_id, :Integer,
+ :dept_name, :String,
+ :manager, {:DataType=>:String, :Lookup=>[:person, :person_id]})
+
+# Insert some department records.
+department_tbl.insert(345, 'Payroll', '000-13-5031')
+department_tbl.insert(442, 'Accounting', '010-10-9999')
+
+# Print department info. Notice how we also print info from the linked
+# person record.
+department_tbl.select.each do |r|
+ puts "\n%s %s %s %s %s" % [r.dept_id, r.dept_name,
+ r.manager.person_id, r.manager.name, r.manager.phone]
+end
62 examples/lookup_field_test/lookup_field_test_2.rb
@@ -0,0 +1,62 @@
+# This script demonstrates how to link a field in the table to an entire
+# record from another table (sometimes called a "lookup table"). This
+# script is different from 'lookup_field_test.rb' because it shows how to
+# use the "lookup_key" table attribute to make it easier to define a
+# Lookup field.
+
+# In the example below, we have a department table. For each department
+# record, the manager field is actually a reference to a record from the
+# person table. This allows us to reference the linked person record
+# through the manager field.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If tables exists, delete them.
+db.drop_table(:department) if db.table_exists?(:department)
+db.drop_table(:person) if db.table_exists?(:person)
+
+# Create a person table. Create lookup table first before the table that
+# uses the lookup table, so that KirbyBase can take advantage of any
+# indexes. Also, we want to create the lookup table first so that we can
+# define a lookup key. We do this by adding a :Key entry to the field type
+# has and assigning true to it's value.
+person_tbl = db.create_table(:person,
+ :person_id, {:DataType=>:String, :Key=>true},
+ :name, :String,
+ :phone, :String
+)
+
+# Insert some person records.
+person_tbl.insert('000-13-5031', 'John Smith', '512.555.1234')
+person_tbl.insert('010-10-9999', 'Jane Doe', '313.724.4230')
+
+# Create a table. We are telling KirbyBase that the manager field is
+# to be linked to the person table. Notice that in this example, since we
+# want the manager field in this table to be linked to the person_id in the
+# person table, which is that table's lookup key field, all we have to
+# specify here is the name of the lookup table, :person.
+department_tbl = db.create_table(:department,
+ :dept_id, :Integer,
+ :dept_name, :String,
+ :manager, {:DataType=>:String, :Lookup=>:person})
+
+# Insert some department records.
+department_tbl.insert(345, 'Payroll', '000-13-5031')
+department_tbl.insert(442, 'Accounting', '010-10-9999')
+
+# Print department info. Notice how we also print info from the linked
+# person record.
+department_tbl.select.each do |r|
+ puts "\n%s %s %s %s %s" % [r.dept_id, r.dept_name,
+ r.manager.person_id, r.manager.name, r.manager.phone]
+end
69 examples/lookup_field_test/the_hal_fulton_feature_test.rb
@@ -0,0 +1,69 @@
+# This script demonstrates how to link a field in the table to an entire
+# record from another table (sometimes called a "lookup table"). This
+# script is different from 'lookup_field_test_2.rb' because it shows how to
+# define a Lookup field in an even easier way, by just specifying the
+# lookup table as the field type for the lookup field. KirbyBase will
+# determine the field type for the lookup field by looking at the field
+# type of the key field of the lookup table. This is a feature that Hal
+# Fulton has been asking for so I named it in honor of him. :)
+
+# In the example below, we have a department table. For each department
+# record, the manager field is actually a reference to a record from the
+# person table. This allows us to reference the linked person record
+# through the manager field.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If tables exists, delete them.
+db.drop_table(:department) if db.table_exists?(:department)
+db.drop_table(:person) if db.table_exists?(:person)
+
+# Create a person table. Create lookup table first before the table that
+# uses the lookup table, so that KirbyBase can take advantage of any
+# indexes. Also, we want to create the lookup table first so that we can
+# define a lookup key. We do this by adding a :Key entry to the field type
+# has and assigning true to it's value.
+person_tbl = db.create_table(:person,
+ :person_id, {:DataType=>:String, :Key=>true},
+ :name, :String,
+ :phone, :String
+)
+
+# Insert some person records.
+person_tbl.insert('000-13-5031', 'John Smith', '512.555.1234')
+person_tbl.insert('010-10-9999', 'Jane Doe', '313.724.4230')
+
+# Create a table. We are telling KirbyBase that the manager field is
+# to be linked to the person table. Notice that in this example, since we
+# want the manager field in this table to be linked to the person_id in the
+# person table, which is that table's lookup key field, all we have to
+# specify here is the name of the lookup table, :person. We don't even
+# have to specify the field type for the :manager field, because
+# KirbyBase will look at the field type definition for :person.person_id
+# to automatically assign :manager the same field type (i.e. :String).
+
+department_tbl = db.create_table(:department,
+ :dept_id, :Integer,
+ :dept_name, :String,
+ :manager, :person)
+
+# Insert some department records.
+department_tbl.insert(345, 'Payroll', '000-13-5031')
+department_tbl.insert(442, 'Accounting', '010-10-9999')
+
+# Print department info. Notice how we also print info from the linked
+# person record.
+department_tbl.select.each do |r|
+ puts "\n%s %s %s %s %s" % [r.dept_id, r.dept_name,
+ r.manager.person_id, r.manager.name, r.manager.phone]
+end
65 examples/many_to_many_test/many_to_many_test.rb
@@ -0,0 +1,65 @@
+# This script demonstrates how you could do many-to-many relationships in
+# KirbyBase.
+
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# Delete tables if they already exist.
+db.drop_table(:author) if db.table_exists?(:author)
+db.drop_table(:book) if db.table_exists?(:book)
+db.drop_table(:book_author) if db.table_exists?(:book_author)
+
+# Create author table. Notice how we are creating a one-to-many link to
+# the book_author table.
+author_tbl = db.create_table(:author,
+ :author_id, :Integer, :name, :String,
+ :books, {:DataType=>:ResultSet,
+ :Link_many=>[:author_id, :book_author, :author_id]}
+)
+
+# Create book table. Notice how we are creating a one-to-many link to
+# the book_author table.
+book_tbl = db.create_table(:book,
+ :book_id, :Integer, :title, :String,
+ :authors, {:DataType=>:ResultSet,
+ :Link_many=>[:book_id, :book_author, :book_id]}
+)
+
+# Create join table that will connect author table and book table.
+book_author_tbl = db.create_table(:book_author, :book_id, :Integer,
+ :author_id, :Integer)
+
+# Insert some author records.
+author_tbl.insert(1, 'Jules Verne', nil)
+author_tbl.insert(2, 'Margaret Weis', nil)
+author_tbl.insert(3, 'Tracy Hickman', nil)
+
+# Insert some book records.
+book_tbl.insert(1, 'Voyage to the Bottom of the Sea', nil)
+book_tbl.insert(2, 'From the Earth to the Moon', nil)
+book_tbl.insert(3, 'Dragons of Winter Night', nil)
+book_tbl.insert(4, 'The Nightmare Lands', nil)
+
+# Insert some records into the book_author table that will link the book
+# table to the author table.
+book_author_tbl.insert(1, 1)
+book_author_tbl.insert(2, 1)
+book_author_tbl.insert(3, 2)
+book_author_tbl.insert(3, 3)
+book_author_tbl.insert(4, 2)
+book_author_tbl.insert(4, 3)
+
+
+# Show all book titles written by Jules Verne.
+author_tbl.select { |r| r.name == 'Jules Verne'
+ }.first.books.each { |b|
+ puts book_tbl.select { |r| r.book_id == b.book_id }.first.title
+}
+puts
+
+# Show the authors of "The Nightmare Lands".
+book_tbl.select { |r| r.title == 'The Nightmare Lands'
+ }.first.authors.each { |a|
+ puts author_tbl.select { |r| r.author_id == a.author_id }.first.name
+}
74 examples/memo_test/memo_test.rb
@@ -0,0 +1,74 @@
+# This script is an example of how you can use KirbyBase's new Memo field
+# type.
+
+require 'kirbybase'
+
+db = KirbyBase.new { |d| d.memo_blob_path = './memos' }
+
+#db = KirbyBase.new(:client, 'localhost', 44444)
+
+
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+# Create a table.
+plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
+ :speed, :Integer, :range, :Integer, :descr, :Memo)
+
+# Create a long string field with embedded newlines for the memo contents.
+memo_string = <<END_OF_STRING
+The P-51 Mustang was the premier Allied fighter aircraft of World War II.
+It's performance and long range allowed it to escort Allied strategic
+bombers on raids deep inside Germany.
+END_OF_STRING
+
+# Create an instance of KBMemo for the memo field.
+memo = KBMemo.new(db, 'P-51.txt', memo_string)
+
+# Insert the new record, including the memo field.
+plane_tbl.insert('P-51', 'USA', 403, 1201, memo)
+
+# Insert another record.
+memo_string = <<END_OF_STRING
+The FW-190 was a World War II German fighter. It was used primarily as an
+interceptor against Allied strategic bombers.
+END_OF_STRING
+
+memo = KBMemo.new(db, 'FW-190.txt', memo_string)
+plane_tbl.insert('FW-190', 'Germany', 399, 499, memo)
+
+# Select all records, print name, country, speed and range on first line.
+# Then, print contents of memo field below.
+plane_tbl.select.each { |r|
+ puts "Name: %s Country: %s Speed: %d Range: %d\n\n" % [r.name,
+ r.country, r.speed, r.range]
+ puts r.descr.contents
+ puts "\n" + "-" * 75 + "\n\n"
+}
+
+
+puts "\n\nNow we will change the memo for the P-51:\n\n"
+
+# Grab the P-51's record.
+rec = plane_tbl.select { |r| r.name == 'P-51' }.first
+
+# Grab the contents of the memo field and add a line to it.
+memo = rec.descr
+memo.contents += "This last line should show up if the memo was changed.\n"
+
+# Now, update the record with the changed contents of the memo field.
+plane_tbl.update {|r| r.name == 'P-51'}.set(:descr => memo)
+
+# Do another select to show that the memo field indeed changed.
+puts plane_tbl.select { |r| r.name == 'P-51' }.first.descr.contents
+
+
+puts "\n\nNow we will change every record's memo field:\n\n"
+
+plane_tbl.update_all { |r|
+ r.descr.contents += "I have added a line to the %s memo.\n\n" % r.name
+}
+
+# Do another select to show that the memo field for each record has
+# indeed changed.
+plane_tbl.select.each { |r| puts r.descr.contents }
0  examples/memo_test/memos/blank.txt
No changes.
77 examples/record_class_test/record_class_test.rb
@@ -0,0 +1,77 @@
+#Test of returning result set composed of instances of user class.
+
+require 'kirbybase'
+
+class Foobar
+ attr_accessor(:recno, :name, :country, :role, :speed, :range,
+ :began_service, :still_flying, :alpha, :beta)
+
+ def Foobar.kb_create(recno, name, country, role, speed, range,
+ began_service, still_flying)
+ name ||= 'No Name!'
+ speed ||= 0
+ began_service ||= Date.today
+ Foobar.new do |x|
+ x.recno = recno
+ x.name = name
+ x.country = country
+ x.role = role
+ x.speed = speed
+ x.range = range
+ x.began_service = began_service
+ x.still_flying = still_flying
+ end
+ end
+
+ def initialize(&block)
+ instance_eval(&block)
+ end
+end
+
+# To run local, single-user, uncomment next line.
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+# Create a table. Notice how you set record_class equal to your class.
+plane_tbl = db.create_table do |t|
+ t.name = :plane
+ t.field_defs = [:name, :String, :country, :String, :role, :String,
+ :speed, :Integer, :range, :Integer, :began_service, :Date,
+ :still_flying, :Boolean]
+ t.encrypt = false
+ t.record_class = Foobar
+end
+
+plane_tbl = db.get_table(:plane)
+
+# Insert a record using an instance of Foobar.
+foo = Foobar.new do |x|
+ x.name = 'Spitfire'
+ x.country = 'Great Britain'
+ x.role = 'Fighter'
+ x.speed = 333
+ x.range = 454
+ x.began_service = Date.new(1936, 1, 1)
+ x.still_flying = true
+ x.alpha = "This variable won't be stored in KirbyBase."
+ x.beta = 'Neither will this one.'
+end
+plane_tbl.insert(foo)
+
+# Notice how select returns instances of Foobar, since it was defined as the
+# record class.
+recs = plane_tbl.select
+puts "Example using #kb_create"
+puts recs[0].class
+
+# Now we are going to change a couple of fields of the Spitfire's Foobar
+# object and update the Spitfire record in the Plane table with the updated
+# Foobar object.
+recs[0].speed = 344
+recs[0].range = 555
+plane_tbl.update(recs[0]) {|r| r.name == 'Spitfire'}
+
+# Here's proof that the table was updated.
+p plane_tbl.select {|r| r.name == 'Spitfire'}
38 examples/record_class_test/record_class_test2.rb
@@ -0,0 +1,38 @@
+#Test of returning result set composed of instances of user class. This
+#example differs from the first in that there is no kb_create method, so
+#KirbyBase will default to create a new instance of the record's custom
+#class and setting each instance attribute to each field's value.
+
+require 'kirbybase'
+
+class Foobar
+ attr_accessor(:recno, :name, :country, :role, :speed, :range,
+ :began_service, :still_flying)
+end
+
+# To run local, single-user, uncomment next line.
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:plane) if db.table_exists?(:plane)
+
+# Create a table. Notice how you set record_class equal to your class.
+plane_tbl = db.create_table do |t|
+ t.name = :plane
+ t.field_defs = [:name, :String, :country, :String, :role, :String,
+ :speed, :Integer, :range, :Integer, :began_service, :Date,
+ :still_flying, :Boolean]
+ t.encrypt = false
+ t.record_class = Foobar
+end
+
+plane_tbl = db.get_table(:plane)
+
+# Insert a record.
+plane_tbl.insert('Spitfire','Great Britain','Fighter',333,454,
+ Date.new(1936, 1, 1),true)
+
+# Notice how select returns instances of Foobar, even there is no
+# kb_create method.
+recs = plane_tbl.select
+p recs.first
46 examples/rename_column_test/rename_column_test.rb
@@ -0,0 +1,46 @@
+# This script is an example of how to rename a column.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If table exists, delete it.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+
+address_book_tbl = db.create_table(:address_book,
+ :firstname, :String, :lastname, :String, :street_address, :String,
+ :city, :String, :phone, :String, :category, :String
+)
+
+# Insert some contact info records.
+address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
+ '111-111-1111', 'Super Hero')
+address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
+ '222-222-2222', 'Cartoon Character')
+address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
+ 'Washington', '333-333-3333', 'President')
+address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
+ 'Any City', '444-444-4444', 'Super Hero')
+
+address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+
+address_book_tbl.rename_column(:phone, :phone_no)
+
+begin
+ address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+ }
+rescue StandardError => e
+ puts e
+ puts;puts
+end
+
+address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone_no]
+}
+puts;puts
+
+p address_book_tbl.field_names
38 examples/rename_table_test/rename_table_test.rb
@@ -0,0 +1,38 @@
+# This script is an example of how to rename a table.
+#
+require 'kirbybase'
+
+db = KirbyBase.new
+
+# If tables exist, delete them.
+db.drop_table(:address_book) if db.table_exists?(:address_book)
+db.drop_table(:contact_list) if db.table_exists?(:contact_list)
+
+address_book_tbl = db.create_table(:address_book,
+ :firstname, :String, :lastname, :String, :street_address, :String,
+ :city, :String, :phone, :String, :category, :String
+)
+
+# Insert some contact info records.
+address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
+ '111-111-1111', 'Super Hero')
+address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
+ '222-222-2222', 'Cartoon Character')
+address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
+ 'Washington', '333-333-3333', 'President')
+address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
+ 'Any City', '444-444-4444', 'Super Hero')
+
+address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+
+contact_list_tbl = db.rename_table(:address_book, :contact_list)
+
+contact_list_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
+}
+puts;puts
+
+p db.tables
47 examples/yaml_field_test/yaml_field_test.rb
@@ -0,0 +1,47 @@
+#Test of YAML field type.
+
+require 'kirbybase'
+
+# To run local, single-user, uncomment next line.
+db = KirbyBase.new
+
+# To run as a client in a multi-user environment, uncomment next line.
+# Also, make sure kbserver.rb is running.
+#db = KirbyBase.new do |d|
+# d.connect_type = :client
+# d.host = 'localhost'
+# d.port = 44444
+#end
+
+# If table exists, delete it.
+db.drop_table(:pet) if db.table_exists?(:pet)
+
+# Create a table.
+pet_tbl = db.create_table(:pet, :name, :String, :pet_type, :String,
+ :born, :Date, :characteristics, :YAML)
+
+pet_tbl.insert('Kirby', 'dog', Date.new(2002, 06, 01),
+ ['cute', 'stinky', 4, 55.6])
+pet_tbl.insert('Mojo', 'cat', Date.new(2000, 04, 01),
+ ['cute', 'soft', '6', 12.25])
+pet_tbl.insert('Goldy', 'fish', Date.new(2004, 10, 10),
+ [])
+
+pet_tbl.select.each { |r|
+ puts '%s %s' % [r.name, r.characteristics[1]]
+}
+
+puts
+
+pet_tbl.select { |r| r.characteristics.include?('stinky') }.each { |r|
+ puts '%s smells like a dog!' % r.name
+}
+
+pet_tbl.update { |r| r.name == 'Goldy' }.set(
+ :characteristics => ['small', 'slimy', 2, 0.02])
+
+puts
+pet_tbl.select.each { |r|
+ puts '%s %s' % [r.name, r.characteristics.join(' ')]
+}
+
BIN  images/blank.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/10.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/11.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/12.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/13.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/14.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/15.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/3.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/4.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/5.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/6.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/7.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/8.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/callouts/9.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/caution.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/client_server.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/example.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/home.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/important.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/kirby1.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/next.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/note.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/prev.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  images/single_user.png
Diff not rendered
BIN  images/smallnew.png
Diff not rendered
BIN  images/tip.png
Diff not rendered
BIN  images/toc-blank.png
Diff not rendered
BIN  images/toc-minus.png
Diff not rendered
BIN  images/toc-plus.png
Diff not rendered
BIN  images/up.png
Diff not rendered
BIN  images/warning.png
Diff not rendered
8 install.rb
@@ -0,0 +1,8 @@
+# Basic installer for fsm
+require 'mkmf'
+require 'fileutils'
+sitedir = Config::CONFIG['sitedir']
+bindir = Config::CONFIG['bindir']
+
+Dir.chdir('lib')
+FileUtils.install('kirbybase.rb', sitedir, :mode => 0644, :verbose => true)
2,324 kirbybaserubymanual.html
@@ -0,0 +1,2324 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 7.0.2" />
+<style type="text/css">
+/* Debug borders */
+p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
+/*
+ border: 1px solid red;
+*/
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a { color: blue; }
+a:visited { color: fuchsia; }
+
+em {
+ font-style: italic;
+}
+
+strong {
+ font-weight: bold;
+}
+
+tt {
+ color: navy;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ font-family: sans-serif;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ border-bottom: 2px solid silver;
+ padding-top: 0.5em;
+}
+
+div.sectionbody {
+ font-family: serif;
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-family: sans-serif;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+span#email {
+}
+span#revision {
+ font-family: sans-serif;
+}
+
+div#footer {
+ font-family: sans-serif;
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble,
+div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-right: 10%;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.5em;
+ margin-bottom: 2.5em;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ font-family: sans-serif;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid silver;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid silver;
+ background: #f4f4f4;
+ padding: 0.5em;
+}
+
+div.quoteblock > div.content {
+ padding-left: 2.0em;
+}
+div.quoteblock .attribution {
+ text-align: right;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 2px solid silver;
+}
+
+div.exampleblock > div.content {
+ border-left: 2px solid silver;
+ padding: 0.5em;
+}
+
+div.verseblock div.content {
+ white-space: pre;
+}
+
+div.imageblock div.content { padding-left: 0; }
+div.imageblock img { border: 1px solid silver; }
+span.image img { border-style: none; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: italic;
+}
+dd > *:first-child {
+ margin-top: 0;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.olist2 {
+ list-style-type: lower-alpha;
+}
+
+div.tableblock > table {
+ border-color: #527bbd;
+ border-width: 3px;
+}
+thead {
+ font-family: sans-serif;
+ font-weight: bold;
+}
+tfoot {
+ font-weight: bold;
+}
+
+div.hlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+td.hlist1 {
+ vertical-align: top;
+ font-style: italic;
+ padding-right: 0.8em;
+}
+td.hlist2 {
+ vertical-align: top;
+}
+
+@media print {
+ div#footer-badges { display: none; }
+}
+/* Workarounds for IE6's broken and incomplete CSS2. */
+
+div.sidebar-content {
+ background: #ffffee;
+ border: 1px solid silver;
+ padding: 0.5em;
+}
+div.sidebar-title, div.image-title {
+ font-family: sans-serif;
+ font-weight: bold;
+ margin-top: 0.0em;
+ margin-bottom: 0.5em;