bitfields 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -38,6 +38,10 @@ Update all users
38
38
  Delete the shop when a user is no longer a seller
39
39
  before_save :delete_shop, :if => lambda{|u| u.changes['seller'] == [true, false]}
40
40
 
41
+ TODO
42
+ ====
43
+ - convenient named scope `User.with_bitfields(:xxx=>true, :yy=>false)`
44
+
41
45
  Author
42
46
  ======
43
47
  [Michael Grosser](http://pragmatig.wordpress.com)
data/Rakefile CHANGED
@@ -1,16 +1,11 @@
1
- require 'spec/rake/spectask'
2
- Spec::Rake::SpecTask.new {|t| t.spec_opts = ['--color']}
1
+ require "rspec/core/rake_task"
2
+ RSpec::Core::RakeTask.new(:spec) do |t|
3
+ t.rspec_opts = '--backtrace --color'
4
+ end
3
5
 
4
6
  task :default do
5
- # test with 2.x
6
- puts `VERSION='~>2' rake spec`
7
-
8
- # gem 'activerecord', '>=3' did not work for me, but just require gets the right version...
9
- require 'active_record'
10
- if ActiveRecord::VERSION::MAJOR >= 3
11
- puts `rake spec`
12
- else
13
- 'install rails 3 to get full test coverage...'
7
+ [2,3].each do |version|
8
+ sh "VERSION='~>#{version}' rake spec" rescue nil
14
9
  end
15
10
  end
16
11
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.5
data/benchmark/1.rb ADDED
@@ -0,0 +1,144 @@
1
+ bit_counts = [2,3,4,5,6,7,8,9,10,11,12,13,14]
2
+ record_counts = (1..20).to_a.map{|i| i * 50_000 }
3
+ use_index = true
4
+ database = ARGV[0]
5
+
6
+ puts "running#{' with index' if use_index} on #{database}"
7
+
8
+ $LOAD_PATH.unshift File.expand_path('lib')
9
+ require 'rubygems'
10
+ gem 'gchartrb'
11
+ require 'google_chart'
12
+ require 'active_record'
13
+ require 'bitfields'
14
+
15
+ def benchmark
16
+ t = Time.now.to_f
17
+ yield
18
+ Time.now.to_f - t
19
+ end
20
+
21
+ def create(bit_counts, count)
22
+ count.times do |i|
23
+ columns = bit_counts.map do |bits_count|
24
+ ["bit_#{bits_count}", rand(2**(bits_count-1))]
25
+ end
26
+ User.create!(Hash[columns])
27
+ end
28
+ end
29
+
30
+ def connect(db)
31
+ if db == 'mysql'
32
+ puts 'using mysql'
33
+ ActiveRecord::Base.establish_connection(
34
+ :adapter => "mysql",
35
+ :database => "bitfields_benchmark"
36
+ )
37
+ else
38
+ puts 'using sqlite'
39
+ ActiveRecord::Base.establish_connection(
40
+ :adapter => "sqlite3",
41
+ :database => ":memory:"
42
+ )
43
+ end
44
+ end
45
+
46
+ def create_model_table(bit_counts, use_index)
47
+ ActiveRecord::Schema.define(:version => 2) do
48
+ drop_table :users rescue nil
49
+ create_table :users do |t|
50
+ bit_counts.each do |bit_count|
51
+ t.integer "bit_#{bit_count}", :default => 0, :null => false
52
+ end
53
+ end
54
+
55
+ if use_index
56
+ bit_counts.each do |bit_count|
57
+ add_index :users, "bit_#{bit_count}"
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def create_model_fields(bit_counts)
64
+ puts "creating model"
65
+ User.class_eval do
66
+ include Bitfields
67
+
68
+ # this takes long for 15/20 bits, maybe needs to be optimized..
69
+ bit_counts.each do |bits_count|
70
+ bits = {}
71
+ 0.upto(bits_count-1) do |bit|
72
+ bits[2**bit] = "bit_#{bits_count}_#{bit}"
73
+ end
74
+
75
+ bitfield "bit_#{bits_count}", bits
76
+ end
77
+ end
78
+ end
79
+
80
+ def test_speed(bit_counts, query_mode)
81
+ result = bit_counts.map do |bit_count|
82
+ sql = User.bitfield_sql({"bit_#{bit_count}_1" => true}, :query_mode => query_mode)
83
+ # puts sql[0..100]
84
+ time = benchmark do
85
+ User.count sql
86
+ end
87
+ puts "#{bit_count} -> #{time}"
88
+ [bit_count, time]
89
+ end
90
+ Hash[result]
91
+ end
92
+
93
+ #determines a unique color based on a name
94
+ def color_for(name)
95
+ name = name.inspect + "some randomness for fun"
96
+ hash = (name.hash % 1_000_000_000).to_s #get a hash of a constant size
97
+ colors = [hash[0..1], hash[2..3], hash[4..5]].map{|c| c.to_f / 100.0 * 16} #use 3 parts of the hash to get numbers from 0 to 15.99
98
+ palette = ('0'..'9').to_a + ('a'..'f').to_a #hex values 0..f
99
+ colors.map{|c| palette[c.floor].to_s * 2} * '' #each color is duplicated and the joined
100
+ end
101
+
102
+ connect(database)
103
+ create_model_table(bit_counts, use_index)
104
+ class User < ActiveRecord::Base
105
+ end
106
+ create_model_fields(bit_counts)
107
+
108
+ puts "creating test data"
109
+ last = 0
110
+
111
+ graphs = {:bit => {}, :in => {}}
112
+ data = record_counts.map do |record_count|
113
+ create(bit_counts, record_count-last)
114
+ puts User.count
115
+ last = record_count
116
+
117
+ puts "testing with #{record_count} records -- bit_operator"
118
+ graphs[:bit][record_count] = test_speed(bit_counts, :bit_operator)
119
+
120
+ puts "testing with #{record_count} records -- in_list"
121
+ graphs[:in][record_count] = test_speed(bit_counts, :in_list)
122
+
123
+ end
124
+
125
+ colors = {:bit => '00xx00', :in => 'xx0000'}
126
+ alpha_num = (('0'..'9').to_a + ('a'..'f').to_a).reverse
127
+ title = "bit-operator vs IN() -- #{use_index ? 'with' : 'without'} index"
128
+ url = GoogleChart::LineChart.new('600x500', title, false) do |line|
129
+ max = 0
130
+ graphs.each do |type, line_data|
131
+ bit_counts.each do |bit_count|
132
+ data = record_counts.map{|rc| line_data[rc][bit_count] }
133
+ name = "#{bit_count}bits (#{type})"
134
+ color = colors[type].sub('xx', alpha_num[bit_count]*2)
135
+ line.data(name, data, color)
136
+ max = [data.max, max].max
137
+ end
138
+ end
139
+
140
+ line.axis :x, :labels => record_counts.map{|c|"#{c/1000}K"}
141
+ line.axis :y, :labels => ['0', "%.3f" % [max*100]]
142
+ end.to_url
143
+
144
+ puts url
data/bitfields.gemspec CHANGED
@@ -1,45 +1,44 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bitfields}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Grosser"]
12
- s.date = %q{2010-04-25}
12
+ s.date = %q{2011-01-19}
13
13
  s.email = %q{grosser.michael@gmail.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.markdown"
16
16
  ]
17
17
  s.files = [
18
18
  "README.markdown",
19
- "Rakefile",
20
- "VERSION",
21
- "bitfields.gemspec",
22
- "lib/bitfields.rb",
23
- "spec/bitfields_spec.rb",
24
- "spec/database.rb",
25
- "spec/spec_helper.rb"
19
+ "Rakefile",
20
+ "VERSION",
21
+ "benchmark/1.rb",
22
+ "bitfields.gemspec",
23
+ "lib/bitfields.rb",
24
+ "spec/bitfields_spec.rb",
25
+ "spec/database.rb",
26
+ "spec/spec_helper.rb"
26
27
  ]
27
28
  s.homepage = %q{http://github.com/grosser/bitfields}
28
- s.rdoc_options = ["--charset=UTF-8"]
29
29
  s.require_paths = ["lib"]
30
- s.rubygems_version = %q{1.3.6}
30
+ s.rubygems_version = %q{1.4.2}
31
31
  s.summary = %q{Save migrations and columns by storing multiple booleans in a single integer.}
32
32
  s.test_files = [
33
- "spec/spec_helper.rb",
34
- "spec/bitfields_spec.rb",
35
- "spec/database.rb"
33
+ "spec/bitfields_spec.rb",
34
+ "spec/database.rb",
35
+ "spec/spec_helper.rb"
36
36
  ]
37
37
 
38
38
  if s.respond_to? :specification_version then
39
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
39
  s.specification_version = 3
41
40
 
42
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
42
  else
44
43
  end
45
44
  else
data/lib/bitfields.rb CHANGED
@@ -58,20 +58,20 @@ module Bitfields
58
58
  found.first
59
59
  end
60
60
 
61
- def bitfield_sql(bit_values)
62
- bits = group_bits_by_column(bit_values)
63
- bits.map{|column, bit_values| bitfield_sql_by_column(column, bit_values) } * ' AND '
61
+ def bitfield_sql(bit_values, options={})
62
+ bits = group_bits_by_column(bit_values).sort_by{|c,v| c.to_s }
63
+ bits.map{|column, bit_values| bitfield_sql_by_column(column, bit_values, options) } * ' AND '
64
64
  end
65
65
 
66
66
  def set_bitfield_sql(bit_values)
67
- columns = group_bits_by_column(bit_values)
68
- columns.map{|column, bit_values| set_bitfield_sql_by_column(column, bit_values) } * ', '
67
+ bits = group_bits_by_column(bit_values).sort_by{|c,v| c.to_s }
68
+ bits.map{|column, bit_values| set_bitfield_sql_by_column(column, bit_values) } * ', '
69
69
  end
70
70
 
71
71
  private
72
72
 
73
- def bitfield_sql_by_column(column, bit_values)
74
- mode = (bitfield_options[column][:query_mode] || :in_list)
73
+ def bitfield_sql_by_column(column, bit_values, options={})
74
+ mode = options[:query_mode] || (bitfield_options[column][:query_mode] || :in_list)
75
75
  case mode
76
76
  when :in_list then
77
77
  max = (bitfields[column].values.max * 2) - 1
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitfields
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ hash: 17
5
+ prerelease:
5
6
  segments:
6
7
  - 0
7
8
  - 1
8
- - 4
9
- version: 0.1.4
9
+ - 5
10
+ version: 0.1.5
10
11
  platform: ruby
11
12
  authors:
12
13
  - Michael Grosser
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-04-25 00:00:00 +02:00
18
+ date: 2011-01-19 00:00:00 +01:00
18
19
  default_executable:
19
20
  dependencies: []
20
21
 
@@ -30,6 +31,7 @@ files:
30
31
  - README.markdown
31
32
  - Rakefile
32
33
  - VERSION
34
+ - benchmark/1.rb
33
35
  - bitfields.gemspec
34
36
  - lib/bitfields.rb
35
37
  - spec/bitfields_spec.rb
@@ -40,32 +42,36 @@ homepage: http://github.com/grosser/bitfields
40
42
  licenses: []
41
43
 
42
44
  post_install_message:
43
- rdoc_options:
44
- - --charset=UTF-8
45
+ rdoc_options: []
46
+
45
47
  require_paths:
46
48
  - lib
47
49
  required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
48
51
  requirements:
49
52
  - - ">="
50
53
  - !ruby/object:Gem::Version
54
+ hash: 3
51
55
  segments:
52
56
  - 0
53
57
  version: "0"
54
58
  required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
55
60
  requirements:
56
61
  - - ">="
57
62
  - !ruby/object:Gem::Version
63
+ hash: 3
58
64
  segments:
59
65
  - 0
60
66
  version: "0"
61
67
  requirements: []
62
68
 
63
69
  rubyforge_project:
64
- rubygems_version: 1.3.6
70
+ rubygems_version: 1.4.2
65
71
  signing_key:
66
72
  specification_version: 3
67
73
  summary: Save migrations and columns by storing multiple booleans in a single integer.
68
74
  test_files:
69
- - spec/spec_helper.rb
70
75
  - spec/bitfields_spec.rb
71
76
  - spec/database.rb
77
+ - spec/spec_helper.rb