ackbar 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,29 @@
1
+
2
+ Version 0.1.1 - Agile Web Development with Rails... and KirbyBase
3
+ =================================================================
4
+
5
+ * Issues & Patches from Jamey Cribbs:
6
+ * Fixed roundtrip of AR::Schema's :datetime type to Ruby's Time objects
7
+ * Base.find now accepts a list of IDs given as string (i.e. "1" and not
8
+ the integer 1).
9
+ * Translating NULL is now case insensitive
10
+ * Fixed Base.count to handle explicit nil as a parameter
11
+
12
+ All these issues were discovered when building the sample 'Depot' app from
13
+ the Pragmatic Programmers' Agile Web Development with Rails
14
+ (http://houseonfire.wordpress.com/2006/02/18/hello-world/)
15
+
16
+ * Other issues:
17
+ * Time values:
18
+ For some reason the AR::Base tests expect Time values where just the hours
19
+ are given (ie. no date) is then assumed to be on Jan 1st, 2000.
20
+ Now if the Time conversion is failing we call string_to_dummy_time.
21
+ * YAML fixes for #serialize
22
+ * Added tests for Ruby code in conditionals and nil values in conditionals
23
+
24
+
1
25
  Version 0.1.0 - Initial Release
26
+ ===============================
2
27
 
3
28
  * Override methods in AR::Base (class and instance) to support KB CRUDs
4
29
 
data/FAQ ADDED
@@ -0,0 +1,117 @@
1
+ = Installation and Startup
2
+
3
+ === I keep getting 'unknown adapter' exceptions when I run any of the scripts
4
+
5
+ If you see something like:
6
+
7
+ /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/
8
+ connection_adapters/abstract/connection_specification.rb:79:in
9
+ `establish_connection': database configuration specifies nonexistent
10
+ kirbybase adapter (ActiveRecord::AdapterNotFound)
11
+
12
+ You need to require 'kirbybase_adpater' *before* or *in* the +Rails::Initializer.run+
13
+ section of the config/environment.rb file of your project.
14
+
15
+ === What do I set in database.yml?
16
+
17
+ The simplest thing is to specify just the adapter and the DB path:
18
+
19
+ development:
20
+ adapter: kirbybase
21
+ database: db/dev
22
+
23
+ The +database+ parameter should point to a directory in which KirbyBase will
24
+ store the .tbl files. There are a few other parameters which will be passed to
25
+ the +KirbyBase.new+ method, but these are untested.
26
+
27
+ = Usage
28
+
29
+ === How do I use code blocks?
30
+
31
+ You can specify Ruby code blocks instead of SQL fragments to the +find+ method
32
+ (and +count+, +delete_all+ and +update_all+ methods) like so:
33
+ Book.find :all, :conditions => lambda{|rec| rec.title =~ /ruby/i}
34
+
35
+ Things to watch out for:
36
+ * The code is run against the KirbyBase row (struct) and not against the Rails
37
+ ActiveRecord::Base object.
38
+ * If you want to do multi-db development you have to wrap this with the
39
+ appropriate checks (+ActiveRecord::Base.connection.adapter_name == 'KirbyBase'+).
40
+
41
+ === Is there a big difference between code blocks and translating SQL fragments?
42
+
43
+ We haven't tested relative performance. These are the considerations for each
44
+ approach:
45
+
46
+ ==== Code Blocks
47
+ * Are more Rubyish
48
+ * Are always correct
49
+ * SQL's LIKE operator isn't supported, so you'd have to use blocks and regexps
50
+ * They don't play as nice with multi-dbs
51
+ * Are run against the KirbyBase row (struct), not the ActiveRecord object
52
+
53
+ ==== SQL Fragments
54
+ * Are a better fir for Rails
55
+ * Are easier to handle in multi-db projects (no ugly +if+s)
56
+ * Are translated, and there's always a chance of something getting missed
57
+ * Don't support SQL's LIKE operator
58
+
59
+ === Are there more online places I can read about Ackbar/KirbyBase on Rails?
60
+
61
+ Sure.
62
+
63
+ ==== Official sites with docos:
64
+ Ackbar: http://ackbar.rubyforge.org
65
+
66
+ KirbyBase: http://netpromi.com/kirbybase_ruby.html
67
+
68
+ ==== Blogs:
69
+ Assaph's blog: http://www.bloglines.com/blog/AssaphMehr
70
+
71
+ Jamey's Blog: http://houseonfire.wordpress.com
72
+
73
+ ==== Sample projects:
74
+ Jamey's blog has a run of the Depot sample app from Agile Web Development with
75
+ Rails. Pimki (http://pimki.rubyforge.org) is currently undergoing extreme
76
+ makeover to run on both KirbyBase and SQLite.
77
+
78
+ = Multi Database Development
79
+
80
+ === Can I use KirbyBase for some tables and an SQL dbms for others?
81
+
82
+ No. To work with KB, the adapter overrides certain methods
83
+ in ActiveRecords::Base and the various Associations to bypass SQL generation.
84
+ These make it not work with other databases.
85
+
86
+ === Where do I start?
87
+
88
+ You should make sure you require +kirbybase_adapter+ *only if using KirbyBase*.
89
+ This is important because of the reasons stated above. You should require the
90
+ adapter when you know it's going to be used, but before the +establish_connection+
91
+ call, i.e. *inside* the +Rails::Initializer.run+ call. You should also create
92
+ a different +database.yml+ file. For example:
93
+
94
+ if ENV['SQLITE3']
95
+ config.database_configuration_file = 'config/sqlite3_db.yml'
96
+ else
97
+ config.database_configuration_file = 'config/kirbybase_db.yml'
98
+ require 'kirbybase_adapter'
99
+ end
100
+
101
+ === What's the comparable method to MySQL's +now+ / Oracle's +sysdate+ calls?
102
+
103
+ Use +Time.now+ or +Date.today+. For example, change:
104
+ :conditions => "date_available <= now()"
105
+ to:
106
+ :conditions => "date_available <= Time.now"
107
+
108
+ === I want to support multiple databases, how do I still do the above?
109
+
110
+ Define a +now+ method for +Object+:
111
+
112
+ class Object
113
+ def now() Time.now() end
114
+ end
115
+
116
+ Now, depending on who is evaluating the conditions (MySQL or KirbyBase),
117
+ different functions will be called... but give the same results.
data/README CHANGED
@@ -11,6 +11,8 @@ Ackbar: http://ackbar.rubyforge.org
11
11
 
12
12
  KirbyBase: http://www.netpromi.com/kirbybase_ruby.html
13
13
 
14
+ Building a sample app with Rails/KirbyBase: http://houseonfire.wordpress.com/2006/02/18/hello-world/
15
+
14
16
  Rails: http://www.rubyonrails.com
15
17
 
16
18
  Pimki: http://pimki.rubyforge.org
@@ -32,7 +34,7 @@ a Rails project for end-user distribution.
32
34
  = What's Covered
33
35
 
34
36
  Ackbar currently passes through a small bootstrap test suite, and through about
35
- 80% of the ActiveRecord test suite. I will never pass 100% of the tests because
37
+ 80% of the ActiveRecord test suite. It will never pass 100% of the tests because
36
38
  KirbyBase does not support all required functionality.
37
39
 
38
40
  Ackbar includes a SQL fragment translator, so that simple cross-database code
@@ -44,9 +46,10 @@ Additionally, you can also provide blocks:
44
46
  or even:
45
47
  Book.find(:all) {|rec| rec.name == 'Pickaxe'}
46
48
 
47
- Most of these changes are around the #find method, bit some apply to #update and
48
- associations. Basic SQL translation should work the same, but you can always
49
- provide custom code to be used. See the CHANGELOG and the tests for examples.
49
+ Most of these changes are around the #find method for the :conditions parameter,
50
+ but some apply to #update and associations. Basic SQL translation should work
51
+ the same, but you can always provide custom code to be used. See the CHANGELOG
52
+ and the tests for examples.
50
53
 
51
54
 
52
55
  = What's Not Covered
@@ -54,7 +57,8 @@ provide custom code to be used. See the CHANGELOG and the tests for examples.
54
57
  * Transactions
55
58
  * Joins, and therefore Eager Associations
56
59
  * Mixins
57
- * Other plugins
60
+ * All the *_by_sql methods
61
+ * Other plugins that do custom SQL
58
62
 
59
63
  On the todo list is support for mixins. It might even be possible to rig something
60
64
  to simulate joins and eager associations, but that is for a later stage. Transactions
@@ -86,3 +90,7 @@ This is because Ackbar overrides certain methods in ActiveRecord::Base and other
86
90
  These methods translate the standard SQL generation to method calls on KirbyBase,
87
91
  and obviously should not be overridden for regular DBs.
88
92
 
93
+ See the FAQ file for more information. Additional information can be found on
94
+ Jamey Cribbs blog on building through the Agile Web Development with Rails Depot
95
+ application with Ackbar/KirbyBase at: http://houseonfire.wordpress.com/
96
+
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ task :default => [:basic_tests, :ar_tests]
11
11
  desc 'Run the unit tests in test directory'
12
12
  Rake::TestTask.new('basic_tests') do |t|
13
13
  t.libs << 'test'
14
- t.pattern = 'test/**/*_test.rb'
14
+ t.pattern = 'test/*_test.rb'
15
15
  t.verbose = true
16
16
  end
17
17
 
@@ -22,11 +22,11 @@ Rake::TestTask.new('ar_tests') do |t|
22
22
  t.verbose = true
23
23
  end
24
24
 
25
-
25
+ require 'kirbybase_adapter'
26
26
  ackbar_spec = Gem::Specification.new do |s|
27
27
  s.platform = Gem::Platform::RUBY
28
28
  s.name = 'ackbar'
29
- s.version = "0.1.0"
29
+ s.version = ActiveRecord::ConnectionAdapters::KirbyBaseAdapter::VERSION
30
30
  s.summary = "ActiveRecord KirbyBase Adapter"
31
31
  s.description = %q{An adapter for Rails::ActiveRecord ORM to the KirbyBase pure-ruby DBMS}
32
32
 
@@ -36,7 +36,7 @@ ackbar_spec = Gem::Specification.new do |s|
36
36
  s.homepage = 'http://ackbar.rubyforge.org'
37
37
 
38
38
  s.has_rdoc = true
39
- s.extra_rdoc_files = %W{README CHANGELOG TODO}
39
+ s.extra_rdoc_files = %W{README CHANGELOG TODO FAQ}
40
40
  s.rdoc_options << '--title' << 'Ackbar -- ActiveRecord Adapter for KirbyBase' <<
41
41
  '--main' << 'README' <<
42
42
  '--exclude' << 'test' <<
@@ -51,6 +51,7 @@ ackbar_spec = Gem::Specification.new do |s|
51
51
  kirbybase_adapter.rb
52
52
  Rakefile
53
53
  CHANGELOG
54
+ FAQ
54
55
  README
55
56
  TODO
56
57
  test/00*.rb
data/TODO CHANGED
@@ -7,6 +7,8 @@ Short Term:
7
7
 
8
8
  Mid Term:
9
9
  * Get the mixins working
10
+ * Run KirbyBase in client/server mode
11
+ * Run through a real web server with FCGI/SCGI etc.
10
12
 
11
13
  Long Term:
12
14
  * Use KB indexes if they exist
@@ -42,7 +42,7 @@ module ActiveRecord
42
42
  def initialize(name, default, sql_type = nil, null = true)
43
43
  super
44
44
  @name = (name == 'recno' ? 'id' : @name)
45
- @text = [:string, :text, 'yaml'].include? @type
45
+ @text = [:string, :text, :yaml].include? @type
46
46
  end
47
47
 
48
48
  def simplified_type(field_type)
@@ -56,7 +56,7 @@ module ActiveRecord
56
56
  when /timestamp/i
57
57
  :timestamp
58
58
  when /time/i
59
- :time
59
+ :datetime
60
60
  when /date/i
61
61
  :date
62
62
  when /clob/i, /text/i
@@ -67,10 +67,16 @@ module ActiveRecord
67
67
  :string
68
68
  when /boolean/i
69
69
  :boolean
70
+ when /yaml/i
71
+ :yaml
70
72
  else
71
- field_type
73
+ field_type.to_sym
72
74
  end
73
75
  end
76
+
77
+ def self.string_to_time(string)
78
+ super or string_to_dummy_time(string)
79
+ end
74
80
  end
75
81
 
76
82
  # The KirbyBase adapter does not need a "db driver", as KirbyBase is a
@@ -88,7 +94,7 @@ module ActiveRecord
88
94
  class KirbyBaseAdapter < AbstractAdapter
89
95
 
90
96
  # Ackbar's own version - i.e. the adapter version, not KirbyBase or Rails.
91
- VERSION = '0.1.0'
97
+ VERSION = '0.1.1'
92
98
 
93
99
  attr_accessor :db
94
100
 
@@ -125,7 +131,7 @@ module ActiveRecord
125
131
  :date => { :DataType => :Date },
126
132
  :binary => { :DataType => :String }, # are KBBlobs better?
127
133
  :boolean => { :DataType => :Boolean },
128
- :YAML => { :DataType => :YAML }
134
+ :yaml => { :DataType => :YAML }
129
135
  }
130
136
  end
131
137
 
@@ -472,10 +478,10 @@ module ActiveRecord
472
478
  records
473
479
  else
474
480
  return args.first if args.first.kind_of?(Array) && args.first.empty?
475
- raise RecordNotFound, "Expecting a list of IDs!" unless args.flatten.all?{|i| i.is_a? Numeric}
481
+ raise RecordNotFound, "Expecting a list of IDs!" unless args.flatten.all?{|i| i.is_a?(Numeric) || (i.is_a?(String) && i.match(/^\d+$/)) }
476
482
 
477
483
  expects_array = ( args.is_a?(Array) and args.first.kind_of?(Array) )
478
- ids = args.flatten.compact.uniq
484
+ ids = args.flatten.compact.collect{ |i| i.to_i }.uniq
479
485
 
480
486
  records = filter ?
481
487
  table.select_by_recno_index(*filter) { |r| ids.include?(r.recno) } :
@@ -633,9 +639,9 @@ module ActiveRecord
633
639
  [/(\w+)\s+IN\s+/, 'rec.\1.in'],
634
640
  [/\.id(\W)/i, '.recno\1'],
635
641
  ['<>', '!='],
636
- ['NULL', 'nil'],
637
- ['AND', 'and'],
638
- ['OR', 'or'],
642
+ [/\bNULL\b/i, 'nil'],
643
+ [/\bAND\b/i, 'and'],
644
+ [/\bOR\b/i, 'or'],
639
645
  ["'%s'", '?'],
640
646
  ['%d', '?'],
641
647
  [/:\w+/, '?'],
@@ -653,7 +659,7 @@ module ActiveRecord
653
659
  # May also be called with a block, e.g.:
654
660
  # Book.count {|rec| rec.author_id == @author.id}
655
661
  def self.count(*args)
656
- if args.empty?
662
+ if args.compact.empty?
657
663
  if block_given?
658
664
  find(:all, :conditions => Proc.new).size
659
665
  else
@@ -689,7 +695,7 @@ module ActiveRecord
689
695
  # in the database.
690
696
  def serialize(attr_name, class_name = Object)
691
697
  __before_ackbar_serialize(attr_name, class_name)
692
- connection.change_column(table_name, attr_name, :YAML)
698
+ connection.change_column(table_name, attr_name, :yaml)
693
699
  end
694
700
  end
695
701
  end
@@ -78,6 +78,9 @@ class KBBasicsTest < Test::Unit::TestCase
78
78
  assert_equal [@andy, @dave], Author.find([1,2])
79
79
  pickaxe_id = $db.get_table(:books).select[0].recno
80
80
  assert_equal @pickaxe, Book.find_by_id(pickaxe_id)
81
+
82
+ assert_equal @andy, Author.find('1')
83
+ assert_equal [@andy, @dave], Author.find('1','2')
81
84
  end
82
85
 
83
86
  def test_find_with_sql_fragments
@@ -201,4 +204,69 @@ class KBBasicsTest < Test::Unit::TestCase
201
204
  Author.decrement_counter 'num_books', [1, 2]
202
205
  assert_equal [0, 1], tbl.select.map{|r| r.num_books}
203
206
  end
207
+
208
+ def test_count
209
+ assert_equal 2, Author.count
210
+ assert_equal 1, Author.count {|rec| rec.name =~ /Andy/}
211
+ assert_equal 1, Author.count("name = 'Dave Thomas'")
212
+ assert_equal 1, Author.count(["name = ?", 'Dave Thomas'])
213
+ assert_equal 2, Author.count(nil)
214
+ end
215
+
216
+ def test_ruby_code_in_conditionals
217
+ DateAndTimeTests.table.insert( Date.new(2005, 1, 1), 1.day.ago )
218
+ records = []
219
+
220
+ assert_nothing_raised { records = DateAndTimeTests.find :all, :conditions => 'date_value > Date.today' }
221
+ assert_equal 0, records.length
222
+
223
+ assert_nothing_raised { records = DateAndTimeTests.find :all, :conditions => 'date_value > Date.new(2004-1-1)' }
224
+ assert_equal 1, records.length
225
+
226
+ assert_nothing_raised { records = DateAndTimeTests.find :all, :conditions => 'time_value > Time.now' }
227
+ assert_equal 0, records.length
228
+
229
+ assert_nothing_raised { records = DateAndTimeTests.find :all, :conditions => 'time_value < Time.now' }
230
+ assert_equal 1, records.length
231
+
232
+ class << Object
233
+ def now() Time.now end
234
+ end
235
+
236
+ assert_nothing_raised { records = DateAndTimeTests.find :all, :conditions => 'time_value > now' }
237
+ assert_equal 0, records.length
238
+
239
+ assert_nothing_raised { records = DateAndTimeTests.find :all, :conditions => 'time_value < now' }
240
+ assert_equal 1, records.length
241
+
242
+ end
243
+
244
+ def test_nil_values
245
+ NilTest.table.insert(nil, 100)
246
+ records = []
247
+
248
+ assert_nothing_raised { records = NilTest.find :all, :conditions => lambda{|rec| rec.nil_value > 100} }
249
+ assert_equal 0, records.length
250
+
251
+ assert_nothing_raised { records = NilTest.find :all, :conditions => lambda{|rec| rec.nil_value > 100 and rec.conditional > 100} }
252
+ assert_equal 0, records.length
253
+
254
+ assert_nothing_raised { records = NilTest.find :all, :conditions => lambda{|rec| rec.nil_value > 100 or rec.conditional == 100} }
255
+ assert_equal 1, records.length
256
+
257
+ assert_nothing_raised { records = NilTest.find :all, :conditions => 'nil_value > 100' }
258
+ assert_equal 0, records.length
259
+
260
+ assert_nothing_raised { records = NilTest.find :all, :conditions => 'nil_value > 100 and conditional > 100' }
261
+ assert_equal 0, records.length
262
+
263
+ assert_nothing_raised { records = NilTest.find :all, :conditions => 'nil_value > 100 and conditional = 100' }
264
+ assert_equal 0, records.length
265
+
266
+ assert_nothing_raised { records = NilTest.find :all, :conditions => 'nil_value > 100 or conditional = 100' }
267
+ assert_equal 1, records.length
268
+
269
+ assert_nothing_raised { records = NilTest.find :all, :conditions => 'nil_value > 100 or conditional > 100' }
270
+ assert_equal 0, records.length
271
+ end
204
272
  end
@@ -15,7 +15,7 @@ class KBSchemaTest < Test::Unit::TestCase
15
15
  recreate_kb_database(true)
16
16
 
17
17
  # check that all tables are in:
18
- assert_equal [:authors, :authors_books, :books, :errata, :pages, :primary_key_tests, :publishers, :schema_info],
18
+ assert_equal [:authors, :authors_books, :books, :date_and_time_tests, :errata, :nil_tests, :pages, :primary_key_tests, :publishers, :schema_info],
19
19
  $db.tables.sort_by{|t| t.to_s }
20
20
  assert_equal $db.tables.map{|t| t.to_s}, @adapter.tables
21
21
 
@@ -24,4 +24,10 @@ end
24
24
 
25
25
  class PrimaryKeyTest < ActiveRecord::Base
26
26
  set_primary_key :pk
27
+ end
28
+
29
+ class NilTest < ActiveRecord::Base
30
+ end
31
+
32
+ class DateAndTimeTests < ActiveRecord::Base
27
33
  end
@@ -38,4 +38,13 @@ ActiveRecord::Schema.define() do
38
38
  t.column 'name', :string
39
39
  end
40
40
 
41
+ create_table :nil_tests, :force => true do |t|
42
+ t.column :nil_value, :integer
43
+ t.column :conditional, :integer
44
+ end
45
+
46
+ create_table :date_and_time_tests, :force => true do |t|
47
+ t.column :date_value, :date
48
+ t.column :time_value, :time
49
+ end
41
50
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: ackbar
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-02-15
6
+ version: 0.1.1
7
+ date: 2006-03-19
8
8
  summary: ActiveRecord KirbyBase Adapter
9
9
  require_paths:
10
10
  - "."
@@ -30,6 +30,7 @@ files:
30
30
  - kirbybase_adapter.rb
31
31
  - Rakefile
32
32
  - CHANGELOG
33
+ - FAQ
33
34
  - README
34
35
  - TODO
35
36
  - test/001_schema_migration_test.rb
@@ -63,6 +64,7 @@ extra_rdoc_files:
63
64
  - README
64
65
  - CHANGELOG
65
66
  - TODO
67
+ - FAQ
66
68
  executables: []
67
69
  extensions: []
68
70
  requirements: []