ohm-arfreaks 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.markdown CHANGED
@@ -20,16 +20,55 @@ This library provides some of them to Ohm::Model.
20
20
 
21
21
  require 'ohm-arfreaks'
22
22
 
23
- class Page < Ohm::Model
23
+ class Video < Ohm::Model
24
24
  attribute :url
25
+ set :tags
25
26
  end
26
27
 
27
- Page.first
28
- # => #<Page:1 url="http://...">
28
+ Video.first
29
+ => #<Video id: 470, url: "a", tags: []>
29
30
 
30
- Page.create!(:url=>...)
31
+ Video.create!(:url=>...)
32
+ Video.new.save!
31
33
 
32
- Page.new.save!
34
+ ### Available Methods
35
+
36
+ def self.primary_key # AR
37
+ def self.columns # AR
38
+ def self.column_names # AR
39
+ def self.content_columns # AR
40
+ def self.columns_hash # AR
41
+ def self.create!(attributes) # AR
42
+ def save! # AR
43
+ def self.first(*args) # AR
44
+ def self.last(*args) # AR
45
+ def self.count(*args) # AR
46
+ def self.delete_all(cond = nil) # AR
47
+ def new_record? # AR
48
+ def attributes # AR
49
+
50
+ (reported by: % grep 'def ' lib/ohm-arfreaks.rb |grep '# AR' )
51
+
52
+ ### NOTE
53
+
54
+ Ohm::Model#attributes returns an names of attributed fields in vanilla ohm gem.
55
+ Of course, it's not familier to our ar-freaks, so it's overwritten by this gem.
56
+
57
+ class Video < Ohm::Model
58
+ attribute :url
59
+ set :tags
60
+ end
61
+
62
+ Video.first.attributes
63
+ => [:url] # in vanilla ohm
64
+ => {:url=>"a", :tags=>[]} # in ohm-arfreaks
65
+
66
+
67
+ Test
68
+ ----
69
+
70
+ % redis-server spec/redis.conf # running on port:6380 in default
71
+ % spec -c spec
33
72
 
34
73
 
35
74
  Homepage
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ AUTHOR = "maiha"
6
6
  EMAIL = "maiha@wota.jp"
7
7
  HOMEPAGE = "http://github.com/maiha/ohm-arfreaks"
8
8
  SUMMARY = "Ohm::Model extensions for AR freaks"
9
- GEM_VERSION = "0.0.1"
9
+ GEM_VERSION = "0.1.0"
10
10
 
11
11
  spec = Gem::Specification.new do |s|
12
12
  s.rubyforge_project = 'asakusarb'
data/lib/ohm-arfreaks.rb CHANGED
@@ -1,34 +1,133 @@
1
1
  module Ohm
2
2
  class Model
3
+ ######################################################################
4
+ ### Columns
5
+
6
+ Column = Struct.new(:name, :type)
7
+
8
+ def self.primary_key # AR
9
+ :id
10
+ end
11
+
12
+ def self.columns # AR
13
+ [Column.new(primary_key, :attribute)] +
14
+ content_columns +
15
+ [:collection, :counter].map do |type|
16
+ __send__("#{type}s").map{|name| Column.new(name, type)}
17
+ end.flatten
18
+ end
19
+
20
+ def self.column_names # AR
21
+ columns.map(&:name)
22
+ end
23
+
24
+ def self.content_columns # AR
25
+ attributes.map{|name| Column.new(name, :attribute)}
26
+ end
27
+
28
+ def self.columns_hash # AR
29
+ columns.inject({}){|h,c| h[c.name] = c; h}
30
+ end
31
+
3
32
  ######################################################################
4
33
  ### Validations
5
34
 
6
35
  RecordNotSaved = Class.new(RuntimeError)
7
36
 
8
- def self.create!(attributes)
37
+ def self.create!(attributes) # AR
9
38
  object = new(attributes)
10
39
  object.save!
11
40
  object
12
41
  end
13
42
 
14
- def save!
43
+ def save! # AR
15
44
  save || raise(RecordNotSaved)
16
45
  end
17
46
 
18
47
  ######################################################################
19
48
  ### Accessor methods
20
49
 
21
- def self.first(*args)
22
- (args.empty? ? all : find(*args)).first
50
+ def self.first(*args) # AR
51
+ (args.empty? ? all : find(*args))[0]
23
52
  end
24
53
 
25
- def self.last(*args)
26
- (args.empty? ? all : find(*args)).last
54
+ def self.last(*args) # AR
55
+ (args.empty? ? all : find(*args))[-1]
27
56
  end
28
57
 
29
- # TODO: should use native 'count' method for performance reason
30
- def self.count(*args)
58
+ def self.count(*args) # AR
31
59
  (args.empty? ? all : find(*args)).size
32
60
  end
61
+
62
+ ######################################################################
63
+ ### ActiveRecord class methods
64
+
65
+ def self.delete_all(cond = nil) # AR
66
+ if cond
67
+ raise NotImplementedError, "Sorry, conditional delete_all is not implemented yet"
68
+ else
69
+ all.each(&:delete)
70
+ end
71
+ end
72
+
73
+ ######################################################################
74
+ ### ActiveRecord instance methods
75
+
76
+ def new_record? # AR
77
+ new?
78
+ end
79
+
80
+ ######################################################################
81
+ ### Overwrite attributes (and related methods)
82
+
83
+ def attributes # AR
84
+ hash = {}
85
+ self.class.attributes.each do |attr|
86
+ hash[attr] = __send__(attr)
87
+ end
88
+ self.class.collections.each do |attr|
89
+ hash[attr] = (begin __send__(attr).to_a; rescue MissingID; []; end)
90
+ end
91
+ self.class.counters.each do |attr|
92
+ hash[attr] = __send__(attr).to_i
93
+ end
94
+ return hash
95
+ end
96
+
97
+ def delete
98
+ delete_from_indices
99
+ delete_attributes(self.class.attributes)
100
+ delete_attributes(self.class.counters)
101
+ delete_attributes(self.class.collections)
102
+ delete_model_membership
103
+ self
104
+ end
105
+
106
+ def inspect
107
+ attrs = attributes.map{|(k,v)| "#{k}: #{v.inspect}"}.join(', ')
108
+ "#<#{self.class} id: #{new_record? ? "nil" : id}, #{attrs}>"
109
+ end
110
+
111
+ # Write attributes using SET
112
+ # This method will be removed once MSET becomes standard.
113
+ def write_with_set
114
+ self.class.attributes.each do |att|
115
+ value = send(att)
116
+ value.to_s.empty? ?
117
+ db.set(key(att), value) :
118
+ db.del(key(att))
119
+ end
120
+ end
121
+
122
+ # Write attributes using MSET
123
+ # This is the preferred method, and will be the only option
124
+ # available once MSET becomes standard.
125
+ def write_with_mset
126
+ unless self.class.attributes.empty?
127
+ rems, adds = self.class.attributes.map { |a| [key(a), send(a)] }.partition { |t| t.last.to_s.empty? }
128
+ db.del(*rems.flatten.compact) unless rems.empty?
129
+ db.mset(adds.flatten) unless adds.empty?
130
+ end
131
+ end
33
132
  end
34
133
  end
@@ -0,0 +1,54 @@
1
+ require File.join(File.dirname(__FILE__), '/spec_helper')
2
+
3
+ describe Ohm::Model do
4
+ provide :attributes do
5
+ subject {
6
+ Video.create!(:url => "http://localhost/")
7
+ }
8
+
9
+ ######################################################################
10
+ ### Attribute
11
+
12
+ its(:attributes) { should be_kind_of(Hash) }
13
+
14
+ it "should contain given attribute" do
15
+ subject.attributes[:url].should == "http://localhost/"
16
+ end
17
+
18
+ ######################################################################
19
+ ### Counter
20
+
21
+ it "should contain given counter" do
22
+ subject.attributes[:viewed].should == 0
23
+ end
24
+
25
+ it "should contain a valid counter value after incr and reload" do
26
+ subject.incr(:viewed)
27
+ subject.attributes[:viewed].should == 1
28
+ Video[subject.id].attributes[:viewed].should == 1
29
+ end
30
+
31
+ ######################################################################
32
+ ### Set
33
+
34
+ it "should contain given set as array" do
35
+ subject.tags.concat "foo"
36
+ subject.attributes[:tags].should be_kind_of(Array)
37
+ end
38
+
39
+ it "should contain given set" do
40
+ subject.tags.concat "foo"
41
+ subject.attributes[:tags].should == ["foo"]
42
+ end
43
+
44
+ it "should contain given set as array" do
45
+ subject.tags.concat "foo"
46
+ subject.tags.concat "bar"
47
+ subject.attributes[:tags].should == ["foo", "bar"]
48
+ end
49
+
50
+ it "should contain empty array when no set given" do
51
+ subject.attributes[:tags].should == []
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,75 @@
1
+ require File.join(File.dirname(__FILE__), '/spec_helper')
2
+
3
+ describe Ohm::Model do
4
+ ######################################################################
5
+ ### columns
6
+
7
+ it do
8
+ Video.should provide(:columns)
9
+ end
10
+
11
+ describe ".columns" do
12
+ it "should return an array of Column" do
13
+ Video.columns.map(&:class).should == [Ohm::Model::Column, Ohm::Model::Column, Ohm::Model::Column, Ohm::Model::Column]
14
+ end
15
+
16
+ it "should contains column names" do
17
+ Video.columns.map(&:name).should == [:id, :url, :tags, :viewed]
18
+ end
19
+
20
+ it "should contains column types" do
21
+ Video.columns.map(&:type).should == [:attribute, :attribute, :collection, :counter]
22
+ end
23
+ end
24
+
25
+ ######################################################################
26
+ ### column_names
27
+
28
+ it do
29
+ Video.should provide(:column_names)
30
+ end
31
+
32
+ describe ".column_names" do
33
+ it "should return an array of Symbol" do
34
+ Video.column_names.map(&:class).uniq.should == [Symbol]
35
+ end
36
+
37
+ it "should return column names" do
38
+ Video.column_names.should == [:id, :url, :tags, :viewed]
39
+ end
40
+ end
41
+
42
+ ######################################################################
43
+ ### content_columns
44
+
45
+ it do
46
+ Video.should provide(:content_columns)
47
+ end
48
+
49
+ describe ".content_columns" do
50
+ it "should return an array of Column" do
51
+ Video.content_columns.map(&:class).uniq.should == [Ohm::Model::Column]
52
+ end
53
+
54
+ it "should contains only attribute columns" do
55
+ Video.content_columns.map(&:type).uniq.should == [:attribute]
56
+ end
57
+
58
+ it "should not contains primary keys" do
59
+ Video.content_columns.map(&:name).should_not include(:id)
60
+ end
61
+ end
62
+
63
+ ######################################################################
64
+ ### columns_hash
65
+
66
+ it do
67
+ Video.should provide(:columns_hash)
68
+ end
69
+
70
+ describe ".columns_hash" do
71
+ it "should return a hash" do
72
+ Video.columns_hash.should be_kind_of(Hash)
73
+ end
74
+ end
75
+ end
data/spec/db/redis.pid ADDED
File without changes
@@ -0,0 +1,15 @@
1
+ module Spec
2
+ module Example
3
+ module Subject
4
+ module ExampleGroupMethods
5
+ def its(*args, &block)
6
+ describe(args.first) do
7
+ define_method(:subject) { super().send(*args) }
8
+ it(&block)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,86 @@
1
+ require File.join(File.dirname(__FILE__), '/spec_helper')
2
+
3
+ describe Ohm::Model do
4
+ ######################################################################
5
+ ### delete_all
6
+
7
+ it do
8
+ Ohm::Model.should provide(:delete_all)
9
+ end
10
+
11
+ describe ".delete_all" do
12
+ before do
13
+ Video.create!(:url=>"a")
14
+ @count = Video.count
15
+ end
16
+
17
+ it "should delete all records" do
18
+ lambda { Video.delete_all }.should change(Video, :count).from(@count).to(0)
19
+ end
20
+
21
+ it "should raise NotImplementedError when args are given" do
22
+ lambda { Video.delete_all(:some_cond) }.should raise_error(NotImplementedError)
23
+ end
24
+ end
25
+
26
+ context "(url 'a' and 'b')" do
27
+ before do
28
+ Video.delete_all
29
+ Video.create!(:url=>"a")
30
+ Video.create!(:url=>"b")
31
+ end
32
+
33
+ ######################################################################
34
+ ### first
35
+ it do
36
+ Ohm::Model.should provide(:first)
37
+ end
38
+
39
+ describe ".first" do
40
+ it "should return an record" do
41
+ # TODO: how to know the orders
42
+ Video.first.url.should match(/\Aa|b\Z/)
43
+ end
44
+ end
45
+
46
+ ######################################################################
47
+ ### all
48
+
49
+ it do
50
+ Ohm::Model.should provide(:all)
51
+ end
52
+
53
+ describe ".all" do
54
+ it "should return all records" do
55
+ Video.all.map(&:url).sort.should == ["a", "b"]
56
+ end
57
+ end
58
+
59
+ ######################################################################
60
+ ### last
61
+
62
+ it do
63
+ Ohm::Model.should provide(:last)
64
+ end
65
+
66
+ describe ".last" do
67
+ it "should return an record" do
68
+ # TODO: how to know the orders
69
+ Video.last.url.should match(/\Aa|b\Z/)
70
+ end
71
+ end
72
+ end
73
+
74
+ ######################################################################
75
+ ### new_recoard?
76
+
77
+ provide :new_record? do
78
+ it "should return true for non saved record" do
79
+ Video.new.new_record?.should == true
80
+ end
81
+
82
+ it "should return false for existing record" do
83
+ Video.create!(:url=>"a").new_record?.should == false
84
+ end
85
+ end
86
+ end
data/spec/model.rb ADDED
@@ -0,0 +1,6 @@
1
+
2
+ class Video < Ohm::Model
3
+ attribute :url
4
+ counter :viewed
5
+ set :tags
6
+ end
@@ -0,0 +1,45 @@
1
+ ######################################################################
2
+ ### provide matcher
3
+ Spec::Matchers.define :provide do |expected|
4
+ match do |obj|
5
+ (obj.public_methods + obj.protected_methods + obj.private_methods).include?(expected.to_s)
6
+ end
7
+ end
8
+
9
+ module Spec
10
+ module Example
11
+ module Subject
12
+ module ExampleGroupMethods
13
+ # == Examples
14
+ #
15
+ # describe User do
16
+ # subject { User.new }
17
+ # provide :name
18
+ #
19
+ # [intead of]
20
+ #
21
+ # it "should provide #name" do
22
+ # methods = subject.public_methods + subject.protected_methods + subject.private_methods
23
+ # methods.should include("name")
24
+ # end
25
+ # end
26
+ #
27
+ def provide(name, &block)
28
+ it "should provide ##{name}" do
29
+ subject.should provide(name)
30
+ end
31
+
32
+ if block
33
+ describe("##{name}") do
34
+ define_method(name) do |*args|
35
+ subject.send(name, *args)
36
+ end
37
+ class_eval(&block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
data/spec/redis.conf ADDED
@@ -0,0 +1,13 @@
1
+ dir ./spec/db
2
+ pidfile ./spec/db/redis.pid
3
+ daemonize yes
4
+ port 6380
5
+ timeout 300
6
+
7
+ save 900 10000
8
+
9
+ loglevel warning
10
+
11
+ logfile stdout
12
+
13
+ databases 16
@@ -0,0 +1,22 @@
1
+
2
+ require 'spec'
3
+ require 'rr'
4
+
5
+ Spec::Runner.configure do |config|
6
+ config.mock_with RR::Adapters::Rspec
7
+ end
8
+
9
+ require 'ohm'
10
+ Ohm.connect(:port=>6380) # this port number should be defined in redis.conf
11
+ Dir.glob(File.join(File.dirname(__FILE__), '/../lib/*.rb')).each{|lib| require lib}
12
+ require File.join(File.dirname(__FILE__), '/its_helper')
13
+ require File.join(File.dirname(__FILE__), '/provide_helper')
14
+ require File.join(File.dirname(__FILE__), '/model')
15
+
16
+ def path(key)
17
+ Pathname(File.join(File.dirname(__FILE__) + "/fixtures/#{key}"))
18
+ end
19
+
20
+ def data(key)
21
+ (@__fixture_data_cache__ ||= {})[key] ||= path(key).read{}
22
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '/spec_helper')
2
+
3
+ describe Video do
4
+ it do
5
+ Video.should provide(:create!)
6
+ end
7
+
8
+ provide :save!
9
+ end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ohm-arfreaks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - maiha
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-05 00:00:00 +09:00
17
+ date: 2010-03-17 00:00:00 +09:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -27,6 +32,16 @@ files:
27
32
  - README.markdown
28
33
  - Rakefile
29
34
  - lib/ohm-arfreaks.rb
35
+ - spec/db/redis.pid
36
+ - spec/attributes_spec.rb
37
+ - spec/redis.conf
38
+ - spec/provide_helper.rb
39
+ - spec/columns_spec.rb
40
+ - spec/model.rb
41
+ - spec/methods_spec.rb
42
+ - spec/its_helper.rb
43
+ - spec/spec_helper.rb
44
+ - spec/validations_spec.rb
30
45
  has_rdoc: true
31
46
  homepage: http://github.com/maiha/ohm-arfreaks
32
47
  licenses: []
@@ -40,18 +55,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
40
55
  requirements:
41
56
  - - ">="
42
57
  - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
43
60
  version: "0"
44
- version:
45
61
  required_rubygems_version: !ruby/object:Gem::Requirement
46
62
  requirements:
47
63
  - - ">="
48
64
  - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
49
67
  version: "0"
50
- version:
51
68
  requirements: []
52
69
 
53
70
  rubyforge_project: asakusarb
54
- rubygems_version: 1.3.5
71
+ rubygems_version: 1.3.6
55
72
  signing_key:
56
73
  specification_version: 3
57
74
  summary: Ohm::Model extensions for AR freaks