akm-selectable_attr 0.3.5 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ /*.gem
2
+ /coverage
3
+ /pkg
4
+ /rdoc
5
+ /selectable_attr_test.sqlite3.db
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Takeshi AKIMA
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,334 @@
1
+ = SelectableAttr
2
+ == Introduction
3
+ selectable_attr は、コードが割り振られるような特定の属性について*コード*、*プログラム上での名前*、
4
+ *表示するための名前*などをまとめて管理するものです。
5
+ http://github.com/akm/selectable_attr/tree/master
6
+
7
+ Railsで使用する場合、selectable_attr_railsと一緒に使うことをオススメします。
8
+ http://github.com/akm/selectable_attr_rails/tree/master
9
+
10
+
11
+ == Install
12
+ === 1. Railsプロジェクトで使う場合
13
+ ==== a. plugin install
14
+ ruby script/plugin install git://github.com/akm/selectable_attr.git
15
+ ruby script/plugin install git://github.com/akm/selectable_attr_rails.git
16
+
17
+ ==== b. gem install
18
+ [sudo] gem install akimatter-selectable_attr akimatter-selectable_attr_rails -s http://gems.github .com
19
+
20
+ === 2. 非Railsで使う場合
21
+ ==== a. gem install
22
+ [sudo] gem install akimatter-selectable_attr -s http://gems.github .com
23
+
24
+
25
+
26
+ == Tutorial
27
+
28
+ === シンプルなパターン
29
+ require 'rubygems'
30
+ require 'selectable_attr'
31
+
32
+ class Person
33
+ include ::SelectableAttr::Base
34
+
35
+ selectable_attr :gender do
36
+ entry '1', :male, '男性'
37
+ entry '2', :female, '女性'
38
+ entry '9', :other, 'その他'
39
+ end
40
+ end
41
+
42
+ 上記のようなクラスがあった場合、以下のようなクラスメソッドを使うことが可能です。
43
+
44
+ irb(main):020:0> Person.gender_ids
45
+ => ["1", "2", "9"]
46
+ irb(main):021:0> Person.gender_keys
47
+ => [:male, :female, :other]
48
+ irb(main):022:0> Person.gender_names
49
+ => ["男性", "女性", "その他"]
50
+ irb(main):023:0> Person.gender_options
51
+ => [["男性", "1"], ["女性", "2"], ["その他", "9"]] # railsでoptions_for_selectメソッドなどに使えます。
52
+ irb(main):024:0> Person.gender_key_by_id("1")
53
+ => :male
54
+ irb(main):025:0> Person.gender_name_by_id("1")
55
+ => "男性"
56
+ irb(main):026:0> Person.gender_id_by_key(:male) # 特定のキーから対応するidを取得できます。
57
+ => "1"
58
+ irb(main):027:0> Person.gender_name_by_key(:male)
59
+ => "男性"
60
+
61
+ また使用可能なインスタンスメソッドには以下のようなものがあります。
62
+
63
+ irb> person = Person.new
64
+ => #<Person:0x133b9d0>
65
+ irb> person.gender_key
66
+ => nil
67
+ irb> person.gender_name
68
+ => nil
69
+ irb> person.gender = "2"
70
+ => "2"
71
+ irb> person.gender_key
72
+ => :female
73
+ irb> person.gender_name
74
+ => "女性"
75
+ irb> person.gender_key = :other
76
+ => :other
77
+ irb> person.gender
78
+ => "9"
79
+ irb> person.gender_name
80
+ => "その他"
81
+
82
+ genderが代入可能なことはもちろん、gender_keyも代入可能です。
83
+ # ただし、gender_nameには代入できません。
84
+
85
+
86
+ === 複数の値を取りうるパターン
87
+ require 'rubygems'
88
+ require 'selectable_attr'
89
+
90
+ class RoomSearch
91
+ include ::SelectableAttr::Base
92
+
93
+ multi_selectable_attr :room_type do
94
+ entry '01', :single, 'シングル'
95
+ entry '02', :twin, 'ツイン'
96
+ entry '03', :double, 'ダブル'
97
+ entry '04', :triple, 'トリプル'
98
+ end
99
+ end
100
+
101
+ multi_selectable_attrを使った場合に使用できるクラスメソッドは、selectable_attrの場合と同じです。
102
+
103
+ irb> room_search = RoomSearch.new
104
+ => #<RoomSearch:0x134a070>
105
+ irb> room_search.room_type_ids
106
+ => []
107
+ irb> room_search.room_type_keys
108
+ => []
109
+ irb> room_search.room_type_names
110
+ => []
111
+ irb> room_search.room_type_selection
112
+ => [false, false, false, false]
113
+ irb> room_search.room_type_keys = [:twin, :double]
114
+ => [:twin, :double]
115
+ irb> room_search.room_type
116
+ => ["02", "03"]
117
+ irb> room_search.room_type_names
118
+ => ["ツイン", "ダブル"]
119
+ irb> room_search.room_type_ids
120
+ => ["02", "03"]
121
+ irb> room_search.room_type = ["01", "04"]
122
+ => ["01", "04"]
123
+ irb> room_search.room_type_keys
124
+ => [:single, :triple]
125
+ irb> room_search.room_type_names
126
+ => ["シングル", "トリプル"]
127
+ irb> room_search.room_type_selection
128
+ => [true, false, false, true]
129
+ irb> room_search.room_type_hash_array
130
+ => [{:select=>true, :key=>:single, :name=>"シングル", :id=>"01"}, {:select=>false, :key=>:twin, :name=>"ツイン", :id=>"02"}, {:select=>false, :key=>:double, :name=>"ダブル", :id=>"03"}, {:select=>true, :key=>:triple, :name=>"トリプル", :id=>"04"}]
131
+ irb> room_search.room_type_hash_array_selected
132
+ => [{:select=>true, :key=>:single, :name=>"シングル", :id=>"01"}, {:select=>true, :key=>:triple, :name=>"トリプル", :id=>"04"}]
133
+
134
+
135
+
136
+ === Entry
137
+ ==== エントリの取得
138
+ エントリは様々な拡張が可能です。例えば以下のようにid、key、name以外の属性を設定することも可能です。
139
+
140
+ require 'rubygems'
141
+ require 'selectable_attr'
142
+
143
+ class Site
144
+ include ::SelectableAttr::Base
145
+
146
+ selectable_attr :protocol do
147
+ entry '01', :http , 'HTTP' , :port => 80
148
+ entry '02', :https, 'HTTPS' , :port => 443
149
+ entry '03', :ssh , 'SSH' , :port => 22
150
+ entry '04', :svn , 'Subversion', :port => 3690
151
+ end
152
+ end
153
+
154
+ クラスメソッドで各エントリを取得することが可能です。
155
+ entry = Site.protocol_entry_by_key(:https)
156
+ entry = Site.protocol_entry_by_id('02')
157
+
158
+ インスタンスメソッドでは以下のように取得できます。
159
+ site = Site.new
160
+ site.protocol_key = :https
161
+ entry = site.protocol_entry
162
+
163
+ ==== エントリの属性
164
+ id, key, nameもそのままメソッドとして用意されています。
165
+ irb> entry.id
166
+ => "02"
167
+ irb> entry.key
168
+ => :https
169
+ irb> entry.name
170
+ => "HTTPS"
171
+
172
+ またオプションの属性もHashのようにアクセス可能です。
173
+ irb> entry[:port]
174
+ => 443
175
+
176
+ to_hashメソッドで、id, key, nameを含むHashを作成します。
177
+ irb> entry.to_hash
178
+ => {:key=>:https, :port=>443, :name=>"HTTPS", :id=>"02"}
179
+
180
+ matchメソッドでid,key,nameを除くオプションの属性群と一致しているかどうかを判断可能です。
181
+
182
+ irb> entry.match?(:port => 22)
183
+ => false
184
+ irb> entry.match?(:port => 443)
185
+ => true
186
+
187
+ # ここではオプションの属性として:portしか設定していないので、matchに渡すHashのキーと値の組み合わせも一つだけですが、
188
+ # 複数ある場合にmatch?がtrueとなるためには、完全に一致している必要があります。
189
+
190
+
191
+ ==== クラスメソッドでのエントリの扱い
192
+ クラスメソッドでエントリを取得する方法として、xxx_entry_by_id, xxx_entry_by_keyを紹介しましたが、
193
+ 全てのエントリで構成される配列を取得するメソッドが xxx_entriesです。
194
+
195
+ irb> entries = Site.protocol_entries
196
+ irb> entries.length
197
+ => 4
198
+
199
+ また、各エントリをto_hashでHashに変換した配列を xxx_hash_arrayメソッドで取得することも可能です。
200
+ irb> Site.protocol_hash_array
201
+ => [
202
+ {:key=>:http, :port=>80, :name=>"HTTP", :id=>"01"},
203
+ {:key=>:https, :port=>443, :name=>"HTTPS", :id=>"02"},
204
+ {:key=>:ssh, :port=>22, :name=>"SSH", :id=>"03"},
205
+ {:key=>:svn, :port=>3690, :name=>"Subversion", :id=>"04"}
206
+ ]
207
+
208
+
209
+ === Enum
210
+ あまり表にでてきませんが、エントリをまとめる役割のオブジェクトがEnumです。
211
+ これはクラスメソッドxxx_enumで取得することができます。
212
+
213
+ irb> enum = Site.protocol_enum
214
+
215
+ Enumには以下のようなメソッドが用意されています。
216
+ irb> enum.entries
217
+ irb> enum.entries.map{|entry| entry[:port]}
218
+ => [80, 443, 22, 3690]
219
+
220
+ EnumはEnumerableをincludeしているため、以下のように記述することも可能です。
221
+ irb> enum.map{|entry| entry[:port]}
222
+ => [80, 443, 22, 3690]
223
+
224
+ irb> enum.entry_by_id("03")
225
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
226
+ irb> enum.entry_by_key(:ssh)
227
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
228
+ irb> enum.entry_by_id_or_key(:ssh)
229
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
230
+ irb> enum.entry_by_id_or_key('03')
231
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
232
+ irb> enum.entry_by_hash(:port => 22)
233
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
234
+
235
+ また、これらのメソッドが面倒と感じるようであれば、以下のような簡単なアクセスも可能です。
236
+ irb> enum['03']
237
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
238
+ irb> enum[:ssh]
239
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
240
+ irb> enum[:port => 22]
241
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
242
+
243
+ またクラスメソッドで紹介したようなxxx_ids, xxx_keys, xxx_namesや、xxx_key_by_idなどのメソッドも用意されています。
244
+ irb> enum.ids
245
+ => ["01", "02", "03", "04"]
246
+ irb> enum.keys
247
+ => [:http, :https, :ssh, :svn]
248
+ irb> enum.names
249
+ => ["HTTP", "HTTPS", "SSH", "Subversion"]
250
+ irb> enum.options
251
+ => [["HTTP", "01"], ["HTTPS", "02"], ["SSH", "03"], ["Subversion", "04"]]
252
+ irb> enum.key_by_id('04')
253
+ => :svn
254
+ irb> enum.id_by_key(:svn)
255
+ => "04"
256
+ irb> enum.name_by_id('04')
257
+ => "Subversion"
258
+ irb> enum.name_by_key(:svn)
259
+ => "Subversion"
260
+ irb> enum.to_hash_array
261
+ => [
262
+ {:key=>:http, :port=>80, :name=>"HTTP", :id=>"01"},
263
+ {:key=>:https, :port=>443, :name=>"HTTPS", :id=>"02"},
264
+ {:key=>:ssh, :port=>22, :name=>"SSH", :id=>"03"},
265
+ {:key=>:svn, :port=>3690, :name=>"Subversion", :id=>"04"}
266
+ ]
267
+
268
+ id, key以外でエントリを特定したい場合はfindメソッドが使えます。
269
+ irb> enum.find(:port => 22)
270
+ => #<SelectableAttr::Enum::Entry:1352a54 @id="03", @key=:ssh, @name="SSH", @options={:port=>22}
271
+
272
+ findメソッドにはブロックを渡すこともできます。
273
+ irb> enum.find{|entry| entry[:port] > 1024}
274
+ => #<SelectableAttr::Enum::Entry:1352a04 @id="04", @key=:svn, @name="Subversion", @options={:port=>3690}
275
+
276
+
277
+ === Entryへのメソッド定義
278
+ entryメソッドにブロックを渡すとエントリのオブジェクトにメソッドを定義することが可能です。
279
+
280
+ require 'rubygems'
281
+ require 'selectable_attr'
282
+
283
+ class Site
284
+ include ::SelectableAttr::Base
285
+
286
+ selectable_attr :protocol do
287
+ entry '01', :http , 'HTTP', :port => 80 do
288
+ def accept?(model)
289
+ # httpで指定された場合はhttpsも可、という仕様
290
+ model.url =~ /^http[s]{0,1}\:\/\//
291
+ end
292
+ end
293
+
294
+ entry '02', :https, 'HTTPS', :port => 443 do
295
+ def accept?(model)
296
+ model.url =~ /^https\:\/\//
297
+ end
298
+ end
299
+
300
+ entry '03', :ssh , 'SSH', :port => 22 do
301
+ def accept?(model)
302
+ false
303
+ end
304
+ end
305
+
306
+ entry '04', :svn , 'Subversion', :port => 3690 do
307
+ def accept?(model)
308
+ model.url =~ /^svn\:\/\/|^svn+ssh\:\/\//
309
+ end
310
+ end
311
+
312
+ end
313
+ end
314
+
315
+ enum = Site.protocol_enum
316
+
317
+ class Project
318
+ attr_accessor :url
319
+ end
320
+ project = Project.new
321
+ project.url = "http://github.com/akm/selectable_attr/tree/master"
322
+
323
+ irb> enum[:http].accept?(project)
324
+ => 0
325
+ irb> enum[:https].accept?(project)
326
+ => nil
327
+
328
+ というようにentryメソッドに渡したブロックは、生成されるエントリオブジェクトのコンテキストでinstance_evalされるので、そのメソッドを定義することが可能です。
329
+
330
+
331
+
332
+
333
+ == Credit
334
+ Copyright (c) 2008 Takeshi AKIMA, released under the MIT lice nse
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>= 1.1.4'
3
+ require 'rake'
4
+ require 'rake/rdoctask'
5
+ require 'spec/rake/spectask'
6
+ require 'spec/rake/verify_rcov'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :spec
10
+
11
+ task :pre_commit => [:spec, 'coverage:verify']
12
+
13
+ desc 'Run all specs under spec/**/*_spec.rb'
14
+ Spec::Rake::SpecTask.new(:spec => 'coverage:clean') do |t|
15
+ t.spec_files = FileList['spec/**/*_spec.rb']
16
+ t.spec_opts = ["-c", "--diff"]
17
+ t.rcov = true
18
+ t.rcov_opts = ["--include-file", "lib\/*\.rb", "--exclude", "spec\/"]
19
+ end
20
+
21
+ desc 'Generate documentation for the selectable_attr plugin.'
22
+ Rake::RDocTask.new(:rdoc) do |rdoc|
23
+ rdoc.rdoc_dir = 'rdoc'
24
+ rdoc.title = 'SelectableAttr'
25
+ rdoc.options << '--line-numbers' << '--inline-source' << '-c UTF-8'
26
+ rdoc.rdoc_files.include('README*')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
29
+
30
+ namespace :coverage do
31
+ desc "Delete aggregate coverage data."
32
+ task(:clean) { rm_f "coverage" }
33
+
34
+ desc "verify coverage threshold via RCov"
35
+ RCov::VerifyTask.new(:verify => :spec) do |t|
36
+ t.threshold = 100.0 # Make sure you have rcov 0.7 or higher!
37
+ t.index_html = 'coverage/index.html'
38
+ end
39
+ end
40
+
41
+ begin
42
+ require 'jeweler'
43
+ Jeweler::Tasks.new do |s|
44
+ s.name = "selectable_attr"
45
+ s.summary = "selectable_attr generates extra methods dynamically"
46
+ s.description = "selectable_attr generates extra methods dynamically for attribute which has options"
47
+ s.email = "akima@gmail.com"
48
+ s.homepage = "http://github.com/akm/selectable_attr/"
49
+ s.authors = ["Takeshi Akima"]
50
+ end
51
+ rescue LoadError
52
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
53
+ end
54
+
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 3
3
- :patch: 5
2
+ :patch: 7
4
3
  :major: 0
4
+ :minor: 3
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'selectable_attr'
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -68,8 +68,8 @@ module SelectableAttr
68
68
  end
69
69
 
70
70
  def selectable_attr_type_for(attr)
71
- single_selectable_attrs.include?(attr) ? :single :
72
- multi_selectable_attrs.include?(attr) ? :multi : nil
71
+ single_selectable_attrs.include?(attr.to_s) ? :single :
72
+ multi_selectable_attrs.include?(attr.to_s) ? :multi : nil
73
73
  end
74
74
 
75
75
  def enum(*args, &block)
@@ -168,7 +168,8 @@ module SelectableAttr
168
168
 
169
169
  def enum_for(attr)
170
170
  base_name = enum_base_name(attr)
171
- const_get("#{base_name.upcase}_ENUM")
171
+ name = "#{base_name.upcase}_ENUM"
172
+ const_defined?(name) ? const_get(name) : nil
172
173
  end
173
174
 
174
175
  def define_accessor(context)
@@ -261,8 +262,6 @@ module SelectableAttr
261
262
  ids = ids ? ids.map(&:to_s) : []
262
263
  update_#{base_name}_hash_array{|hash|ids.include?(hash[:id].to_s)}
263
264
  end
264
- EOS
265
- self.module_eval(<<-"EOS")
266
265
  def #{base_name}_hash_array
267
266
  self.class.#{base_name}_to_hash_array(self.class.#{base_name}_enum, #{attr})
268
267
  end
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  module SelectableAttr
2
3
 
3
4
  class Enum
@@ -149,7 +150,13 @@ module SelectableAttr
149
150
  def to_hash
150
151
  (@options || {}).merge(:id => @id, :key => @key, :name => name)
151
152
  end
152
-
153
+
154
+ def inspect
155
+ # object_idを2倍にしているのは通常のinspectと合わせるためです。
156
+ '#<%s:%x @id=%s, @key=%s, @name=%s, @options=%s' % [
157
+ self.class.name, object_id * 2, id.inspect, key.inspect, name.inspect, @options.inspect]
158
+ end
159
+
153
160
  NULL = new(nil, nil, nil, nil) do
154
161
  def null?; true; end
155
162
  def name; nil; end
@@ -0,0 +1,54 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{selectable_attr}
5
+ s.version = "0.3.7"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Takeshi Akima"]
9
+ s.date = %q{2009-08-17}
10
+ s.description = %q{selectable_attr generates extra methods dynamically for attribute which has options}
11
+ s.email = %q{akima@gmail.com}
12
+ s.extra_rdoc_files = [
13
+ "README"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "MIT-LICENSE",
18
+ "README",
19
+ "Rakefile",
20
+ "VERSION.yml",
21
+ "init.rb",
22
+ "install.rb",
23
+ "lib/selectable_attr.rb",
24
+ "lib/selectable_attr/base.rb",
25
+ "lib/selectable_attr/enum.rb",
26
+ "lib/selectable_attr/version.rb",
27
+ "selectable_attr.gemspec",
28
+ "spec/selectable_attr_base_alias_spec.rb",
29
+ "spec/selectable_attr_enum_spec.rb",
30
+ "spec/spec_helper.rb",
31
+ "tasks/selectable_attr_tasks.rake",
32
+ "uninstall.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/akm/selectable_attr/}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.4}
38
+ s.summary = %q{selectable_attr generates extra methods dynamically}
39
+ s.test_files = [
40
+ "spec/selectable_attr_base_alias_spec.rb",
41
+ "spec/selectable_attr_enum_spec.rb",
42
+ "spec/spec_helper.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
@@ -70,66 +70,72 @@ describe SelectableAttr do
70
70
  include ::SelectableAttr::Base
71
71
  end
72
72
 
73
- class EnumMock1 < EnumBase
74
- selectable_attr :enum1, :default => 2 do
75
- entry 1, :entry1, "エントリ1"
76
- entry 2, :entry2, "エントリ2"
77
- entry 3, :entry3, "エントリ3"
78
- end
79
- end
80
-
81
- class EnumMock1WithEnum < EnumBase
82
- selectable_attr :enum1, :default => 2 do
83
- entry 1, :entry1, "エントリ1"
84
- entry 2, :entry2, "エントリ2"
85
- entry 3, :entry3, "エントリ3"
73
+ describe "selectable_attr with default" do
74
+ class EnumMock1 < EnumBase
75
+ selectable_attr :enum1, :default => 2 do
76
+ entry 1, :entry1, "エントリ1"
77
+ entry 2, :entry2, "エントリ2"
78
+ entry 3, :entry3, "エントリ3"
79
+ end
86
80
  end
87
- end
88
-
89
- it "test_selectable_attr1" do
90
- assert_enum_class_methods(EnumMock1)
91
- mock1 = EnumMock1.new
92
- mock1.enum1.should == 2
93
- assert_single_enum_instance_methods(mock1)
94
-
95
- assert_enum_class_methods(EnumMock1WithEnum)
96
- mock1 = EnumMock1WithEnum.new
97
- mock1.enum1.should == 2
98
- assert_single_enum_instance_methods(mock1)
99
- end
100
-
101
81
 
102
- class EnumMock2 < EnumBase
103
- attr_enumeable_base do |attr|
104
- attr.to_s.gsub(/(.*)_code(.*)$/){"#{$1}#{$2}"}
82
+ class EnumMock1WithEnum < EnumBase
83
+ selectable_attr :enum1, :default => 2 do
84
+ entry 1, :entry1, "エントリ1"
85
+ entry 2, :entry2, "エントリ2"
86
+ entry 3, :entry3, "エントリ3"
87
+ end
105
88
  end
106
89
 
107
- selectable_attr :enum_code1 do
108
- entry 1, :entry1, "エントリ1"
109
- entry 2, :entry2, "エントリ2"
110
- entry 3, :entry3, "エントリ3"
90
+ it "test_selectable_attr1" do
91
+ assert_enum_class_methods(EnumMock1)
92
+ mock1 = EnumMock1.new
93
+ mock1.enum1.should == 2
94
+ assert_single_enum_instance_methods(mock1)
95
+
96
+ assert_enum_class_methods(EnumMock1WithEnum)
97
+ mock1 = EnumMock1WithEnum.new
98
+ mock1.enum1.should == 2
99
+ assert_single_enum_instance_methods(mock1)
100
+
101
+ EnumMock1.selectable_attr_type_for(:enum1).should == :single
102
+ EnumMock1WithEnum.selectable_attr_type_for(:enum1).should == :single
111
103
  end
112
104
  end
105
+
113
106
 
114
- class EnumMock2WithEnum < EnumBase
115
- attr_enumeable_base do |attr|
116
- attr.to_s.gsub(/(.*)_code(.*)$/){"#{$1}#{$2}"}
107
+ describe "attr_enumeable_base" do
108
+ class EnumMock2 < EnumBase
109
+ attr_enumeable_base do |attr|
110
+ attr.to_s.gsub(/(.*)_code(.*)$/){"#{$1}#{$2}"}
111
+ end
112
+
113
+ selectable_attr :enum_code1 do
114
+ entry 1, :entry1, "エントリ1"
115
+ entry 2, :entry2, "エントリ2"
116
+ entry 3, :entry3, "エントリ3"
117
+ end
117
118
  end
118
119
 
119
- enum :enum_code1 do
120
- entry 1, :entry1, "エントリ1"
121
- entry 2, :entry2, "エントリ2"
122
- entry 3, :entry3, "エントリ3"
120
+ class EnumMock2WithEnum < EnumBase
121
+ attr_enumeable_base do |attr|
122
+ attr.to_s.gsub(/(.*)_code(.*)$/){"#{$1}#{$2}"}
123
+ end
124
+
125
+ enum :enum_code1 do
126
+ entry 1, :entry1, "エントリ1"
127
+ entry 2, :entry2, "エントリ2"
128
+ entry 3, :entry3, "エントリ3"
129
+ end
123
130
  end
124
- end
125
131
 
126
- it "test_selectable_attr2" do
127
- assert_enum_class_methods(EnumMock2)
128
- assert_single_enum_instance_methods(EnumMock2.new, :enum_code1)
129
- assert_enum_class_methods(EnumMock2WithEnum)
130
- assert_single_enum_instance_methods(EnumMock2WithEnum.new, :enum_code1)
132
+ it "test_selectable_attr2" do
133
+ assert_enum_class_methods(EnumMock2)
134
+ assert_single_enum_instance_methods(EnumMock2.new, :enum_code1)
135
+ assert_enum_class_methods(EnumMock2WithEnum)
136
+ assert_single_enum_instance_methods(EnumMock2WithEnum.new, :enum_code1)
137
+ end
131
138
  end
132
-
133
139
 
134
140
 
135
141
  def assert_multi_enum_instance_methods(obj, patterns)
@@ -210,122 +216,215 @@ describe SelectableAttr do
210
216
  obj.enum_array1_ids = "2"; obj.enum_array1.should == patterns[2]
211
217
  end
212
218
 
213
- class EnumMock3 < EnumBase
214
- multi_selectable_attr :enum_array1, :convert_with => :binary_string do
215
- entry 1, :entry1, "エントリ1"
216
- entry 2, :entry2, "エントリ2"
217
- entry 3, :entry3, "エントリ3"
219
+ describe ":convert_with => :binary_string" do
220
+ class EnumMock3 < EnumBase
221
+ multi_selectable_attr :enum_array1, :convert_with => :binary_string do
222
+ entry 1, :entry1, "エントリ1"
223
+ entry 2, :entry2, "エントリ2"
224
+ entry 3, :entry3, "エントリ3"
225
+ end
218
226
  end
219
- end
220
-
221
- class EnumMock3WithEnumArray < EnumBase
222
- enum_array :enum_array1, :convert_with => :binary_string do
223
- entry 1, :entry1, "エントリ1"
224
- entry 2, :entry2, "エントリ2"
225
- entry 3, :entry3, "エントリ3"
227
+
228
+ class EnumMock3WithEnumArray < EnumBase
229
+ enum_array :enum_array1, :convert_with => :binary_string do
230
+ entry 1, :entry1, "エントリ1"
231
+ entry 2, :entry2, "エントリ2"
232
+ entry 3, :entry3, "エントリ3"
233
+ end
226
234
  end
227
- end
228
-
229
- it "test_multi_selectable_attr_with_binary_string" do
230
- expected = (0..7).map{|i| '%-03b' % i} # ["000", "001", "010", "011", "100", "101", "110", "111"]
231
- assert_enum_class_methods(EnumMock3, :enum_array1)
232
- assert_multi_enum_instance_methods(EnumMock3.new, expected)
233
- assert_enum_class_methods(EnumMock3WithEnumArray, :enum_array1)
234
- assert_multi_enum_instance_methods(EnumMock3WithEnumArray.new, expected)
235
- end
236
235
 
237
- class EnumMock4 < EnumBase
238
- multi_selectable_attr :enum_array1 do
239
- entry 1, :entry1, "エントリ1"
240
- entry 2, :entry2, "エントリ2"
241
- entry 3, :entry3, "エントリ3"
236
+ it "test_multi_selectable_attr_with_binary_string" do
237
+ expected = (0..7).map{|i| '%-03b' % i} # ["000", "001", "010", "011", "100", "101", "110", "111"]
238
+ assert_enum_class_methods(EnumMock3, :enum_array1)
239
+ assert_multi_enum_instance_methods(EnumMock3.new, expected)
240
+ assert_enum_class_methods(EnumMock3WithEnumArray, :enum_array1)
241
+ assert_multi_enum_instance_methods(EnumMock3WithEnumArray.new, expected)
242
+ EnumMock3.selectable_attr_type_for(:enum_array1).should == :multi
242
243
  end
243
244
  end
244
-
245
- class EnumMock4WithEnumArray < EnumBase
246
- enum_array :enum_array1 do
247
- entry 1, :entry1, "エントリ1"
248
- entry 2, :entry2, "エントリ2"
249
- entry 3, :entry3, "エントリ3"
245
+
246
+ describe "multi_selectable_attr" do
247
+ class EnumMock4 < EnumBase
248
+ multi_selectable_attr :enum_array1 do
249
+ entry 1, :entry1, "エントリ1"
250
+ entry 2, :entry2, "エントリ2"
251
+ entry 3, :entry3, "エントリ3"
252
+ end
250
253
  end
251
- end
252
-
253
- it "test_multi_selectable_attr2" do
254
- # [[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
255
- expected =
256
- (0..7).map do |i|
257
- s = '%03b' % i
258
- a = s.split('').map{|v| v.to_i}
259
- ret = []
260
- a.each_with_index{|val, pos| ret << pos + 1 if val == 1}
261
- ret
254
+
255
+ class EnumMock4WithEnumArray < EnumBase
256
+ enum_array :enum_array1 do
257
+ entry 1, :entry1, "エントリ1"
258
+ entry 2, :entry2, "エントリ2"
259
+ entry 3, :entry3, "エントリ3"
262
260
  end
263
- assert_enum_class_methods(EnumMock4, :enum_array1)
264
- assert_multi_enum_instance_methods(EnumMock4.new, expected)
265
- assert_enum_class_methods(EnumMock4WithEnumArray, :enum_array1)
266
- assert_multi_enum_instance_methods(EnumMock4WithEnumArray.new, expected)
267
- end
261
+ end
268
262
 
269
- class EnumMock5 < EnumBase
270
- multi_selectable_attr :enum_array1, :convert_with => :comma_string do
271
- entry 1, :entry1, "エントリ1"
272
- entry 2, :entry2, "エントリ2"
273
- entry 3, :entry3, "エントリ3"
263
+ it "test_multi_selectable_attr2" do
264
+ # [[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
265
+ expected =
266
+ (0..7).map do |i|
267
+ s = '%03b' % i
268
+ a = s.split('').map{|v| v.to_i}
269
+ ret = []
270
+ a.each_with_index{|val, pos| ret << pos + 1 if val == 1}
271
+ ret
272
+ end
273
+ assert_enum_class_methods(EnumMock4, :enum_array1)
274
+ assert_multi_enum_instance_methods(EnumMock4.new, expected)
275
+ assert_enum_class_methods(EnumMock4WithEnumArray, :enum_array1)
276
+ assert_multi_enum_instance_methods(EnumMock4WithEnumArray.new, expected)
274
277
  end
275
278
  end
276
-
277
- class EnumMock5WithEnumArray < EnumBase
278
- enum_array :enum_array1, :convert_with => :comma_string do
279
- entry 1, :entry1, "エントリ1"
280
- entry 2, :entry2, "エントリ2"
281
- entry 3, :entry3, "エントリ3"
279
+
280
+ describe "convert_with" do
281
+ class EnumMock5 < EnumBase
282
+ multi_selectable_attr :enum_array1, :convert_with => :comma_string do
283
+ entry 1, :entry1, "エントリ1"
284
+ entry 2, :entry2, "エントリ2"
285
+ entry 3, :entry3, "エントリ3"
286
+ end
287
+ end
288
+
289
+ class EnumMock5WithEnumArray < EnumBase
290
+ enum_array :enum_array1, :convert_with => :comma_string do
291
+ entry 1, :entry1, "エントリ1"
292
+ entry 2, :entry2, "エントリ2"
293
+ entry 3, :entry3, "エントリ3"
294
+ end
295
+ end
296
+
297
+ it "test_multi_selectable_attr_with_comma_string" do
298
+ # ["", "3", "2", "2,3", "1", "1,3", "1,2", "1,2,3"]
299
+ expected =
300
+ (0..7).map do |i|
301
+ s = '%03b' % i
302
+ a = s.split('').map{|v| v.to_i}
303
+ ret = []
304
+ a.each_with_index{|val, pos| ret << pos + 1 if val == 1}
305
+ ret.join(',')
306
+ end
307
+ assert_enum_class_methods(EnumMock5, :enum_array1)
308
+ assert_multi_enum_instance_methods(EnumMock5.new, expected)
309
+ assert_enum_class_methods(EnumMock5WithEnumArray, :enum_array1)
310
+ assert_multi_enum_instance_methods(EnumMock5WithEnumArray.new, expected)
282
311
  end
283
312
  end
284
-
285
- it "test_multi_selectable_attr_with_comma_string" do
286
- # ["", "3", "2", "2,3", "1", "1,3", "1,2", "1,2,3"]
287
- expected =
288
- (0..7).map do |i|
289
- s = '%03b' % i
290
- a = s.split('').map{|v| v.to_i}
291
- ret = []
292
- a.each_with_index{|val, pos| ret << pos + 1 if val == 1}
293
- ret.join(',')
313
+
314
+ describe "selectable_attr_name_pattern" do
315
+ class EnumMock6 < EnumBase
316
+ # self.selectable_attr_name_pattern = /(_cd$|_code$|_cds$|_codes$)/
317
+ selectable_attr :category_id do
318
+ entry "01", :category1, "カテゴリ1"
319
+ entry "02", :category2, "カテゴリ2"
294
320
  end
295
- assert_enum_class_methods(EnumMock5, :enum_array1)
296
- assert_multi_enum_instance_methods(EnumMock5.new, expected)
297
- assert_enum_class_methods(EnumMock5WithEnumArray, :enum_array1)
298
- assert_multi_enum_instance_methods(EnumMock5WithEnumArray.new, expected)
321
+ end
322
+
323
+ class EnumMock7 < EnumBase
324
+ self.selectable_attr_name_pattern = /(_cd$|_id$|_cds$|_ids$)/
325
+ selectable_attr :category_id do
326
+ entry "01", :category1, "カテゴリ1"
327
+ entry "02", :category2, "カテゴリ2"
328
+ end
329
+ end
330
+
331
+ it "test_selectable_attr_name_pattern" do
332
+ EnumMock6.selectable_attr_name_pattern.should == /(_cd$|_code$|_cds$|_codes$)/
333
+ EnumMock6.respond_to?(:category_enum).should == false
334
+ EnumMock6.respond_to?(:category_id_enum).should == true
335
+ EnumMock6.new.respond_to?(:category_key).should == false
336
+ EnumMock6.new.respond_to?(:category_id_key).should == true
337
+
338
+ EnumMock7.selectable_attr_name_pattern.should == /(_cd$|_id$|_cds$|_ids$)/
339
+ EnumMock7.respond_to?(:category_enum).should == true
340
+ EnumMock7.respond_to?(:category_id_enum).should == false
341
+ EnumMock7.new.respond_to?(:category_key).should == true
342
+ EnumMock7.new.respond_to?(:category_id_key).should == false
343
+ end
299
344
  end
345
+
346
+ describe "has_attr" do
347
+ class ConnectableMock1 < EnumBase
348
+ class << self
349
+ def columns; end
350
+ def connection; end
351
+ def connectec?; end
352
+ def table_exists?; end
353
+ end
354
+ end
355
+
356
+ it "should return false if column does exist" do
357
+ ConnectableMock1.should_receive(:connected?).and_return(true)
358
+ ConnectableMock1.should_receive(:table_exists?).and_return(true)
359
+ ConnectableMock1.should_receive(:columns).and_return([mock(:column1, :name => :column1)])
360
+ ConnectableMock1.has_attr(:column1).should == true
361
+ end
300
362
 
301
- class EnumMock6 < EnumBase
302
- # self.selectable_attr_name_pattern = /(_cd$|_code$|_cds$|_codes$)/
303
- selectable_attr :category_id do
304
- entry "01", :category1, "カテゴリ1"
305
- entry "02", :category2, "カテゴリ2"
363
+ it "should return false if column doesn't exist" do
364
+ ConnectableMock1.should_receive(:connected?).and_return(true)
365
+ ConnectableMock1.should_receive(:table_exists?).and_return(true)
366
+ ConnectableMock1.should_receive(:columns).and_return([mock(:column1, :name => :column1)])
367
+ ConnectableMock1.has_attr(:unknown_column).should == false
368
+ end
369
+
370
+ it "should return nil unless connected" do
371
+ ConnectableMock1.should_receive(:connected?).and_return(false)
372
+ ConnectableMock1.should_receive(:table_exists?).and_return(false)
373
+ ConnectableMock1.has_attr(:unknown_column).should == false
374
+ end
375
+
376
+ it "should return nil if can't connection cause of Exception" do
377
+ ConnectableMock1.should_receive(:connected?).twice.and_return(false)
378
+ ConnectableMock1.should_receive(:connection).and_raise(IOError.new("can't connect to DB"))
379
+ ConnectableMock1.has_attr(:unknown_column).should == nil
306
380
  end
307
381
  end
308
-
309
- class EnumMock7 < EnumBase
310
- self.selectable_attr_name_pattern = /(_cd$|_id$|_cds$|_ids$)/
311
- selectable_attr :category_id do
312
- entry "01", :category1, "カテゴリ1"
313
- entry "02", :category2, "カテゴリ2"
382
+
383
+ describe "enum_for" do
384
+ class EnumMock10 < EnumBase
385
+ selectable_attr :enum1, :default => 2 do
386
+ entry 1, :entry1, "エントリ1"
387
+ entry 2, :entry2, "エントリ2"
388
+ entry 3, :entry3, "エントリ3"
389
+ end
390
+ end
391
+
392
+ it "return constant by Symbol access" do
393
+ enum1 = EnumMock10.enum_for(:enum1)
394
+ enum1.class.should == SelectableAttr::Enum
314
395
  end
396
+
397
+ it "return constant by String access" do
398
+ enum1 = EnumMock10.enum_for('enum1')
399
+ enum1.class.should == SelectableAttr::Enum
400
+ end
401
+
402
+ it "return nil for unexist attr" do
403
+ enum1 = EnumMock10.enum_for('unexist_attr')
404
+ enum1.should == nil
405
+ end
406
+
315
407
  end
316
-
317
- it "test_selectable_attr_name_pattern" do
318
- EnumMock6.selectable_attr_name_pattern.should == /(_cd$|_code$|_cds$|_codes$)/
319
- EnumMock6.respond_to?(:category_enum).should == false
320
- EnumMock6.respond_to?(:category_id_enum).should == true
321
- EnumMock6.new.respond_to?(:category_key).should == false
322
- EnumMock6.new.respond_to?(:category_id_key).should == true
408
+
409
+ describe "define_accessor" do
410
+ class DefiningMock1 < EnumBase
411
+ class << self
412
+ def attr_accessor_with_default(*args); end
413
+ end
414
+ end
323
415
 
324
- EnumMock7.selectable_attr_name_pattern.should == /(_cd$|_id$|_cds$|_ids$)/
325
- EnumMock7.respond_to?(:category_enum).should == true
326
- EnumMock7.respond_to?(:category_id_enum).should == false
327
- EnumMock7.new.respond_to?(:category_key).should == true
328
- EnumMock7.new.respond_to?(:category_id_key).should == false
416
+ it "should call attr_accessor_with_default when both of attr_accessor and default are given" do
417
+ DefiningMock1.should_receive(:attr_accessor_with_default).with(:enum1, 1)
418
+ DefiningMock1.define_accessor(:attr => :enum1, :attr_accessor => true, :default => 1)
419
+ end
420
+
421
+ it "should call attr_accessor_with_default when default are given but attr_accessor is not TRUE" do
422
+ $stderr.should_receive(:puts).with("WARNING! :default option ignored for enum1")
423
+ DefiningMock1.define_accessor(:attr => :enum1, :attr_accessor => false, :default => 1)
424
+ end
425
+
426
+
329
427
  end
330
428
 
429
+
331
430
  end
@@ -114,4 +114,16 @@ describe SelectableAttr::Enum do
114
114
  ]
115
115
  end
116
116
 
117
+ describe "find" do
118
+ it "with options" do
119
+ InetAccess.find(:protocol => 'http://').should == InetAccess[2]
120
+ InetAccess.find(:protocol => 'svn+ssh://').should == SelectableAttr::Enum::Entry::NULL
121
+ end
122
+
123
+ it "with block" do
124
+ InetAccess.find{|entry| entry.key.to_s =~ /tp/}.should == InetAccess[3]
125
+ InetAccess.find{|entry| entry.key.to_s =~ /XXXXXX/}.should == SelectableAttr::Enum::Entry::NULL
126
+ end
127
+ end
128
+
117
129
  end
@@ -0,0 +1,18 @@
1
+ require 'yaml'
2
+ require 'yaml_waml'
3
+
4
+ namespace :i18n do
5
+ namespace :selectable_attr do
6
+ task :load_all_models => :environment do
7
+ Dir.glob(File.join(RAILS_ROOT, 'app', 'models', '**', '*.rb')) do |file_name|
8
+ require file_name
9
+ end
10
+ end
11
+
12
+ desc "Export i18n resources for selectable_attr entries"
13
+ task :export => :"i18n:selectable_attr:load_all_models" do
14
+ obj = {I18n.locale => SelectableAttr::Enum.i18n_export}
15
+ puts YAML.dump(obj)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: akm-selectable_attr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takeshi Akima
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-23 00:00:00 -08:00
12
+ date: 2009-08-17 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -19,23 +19,31 @@ executables: []
19
19
 
20
20
  extensions: []
21
21
 
22
- extra_rdoc_files: []
23
-
22
+ extra_rdoc_files:
23
+ - README
24
24
  files:
25
+ - .gitignore
26
+ - MIT-LICENSE
27
+ - README
28
+ - Rakefile
25
29
  - VERSION.yml
26
- - lib/selectable_attr
30
+ - init.rb
31
+ - install.rb
32
+ - lib/selectable_attr.rb
27
33
  - lib/selectable_attr/base.rb
28
34
  - lib/selectable_attr/enum.rb
29
35
  - lib/selectable_attr/version.rb
30
- - lib/selectable_attr.rb
36
+ - selectable_attr.gemspec
31
37
  - spec/selectable_attr_base_alias_spec.rb
32
38
  - spec/selectable_attr_enum_spec.rb
33
39
  - spec/spec_helper.rb
34
- has_rdoc: true
40
+ - tasks/selectable_attr_tasks.rake
41
+ - uninstall.rb
42
+ has_rdoc: false
35
43
  homepage: http://github.com/akm/selectable_attr/
44
+ licenses:
36
45
  post_install_message:
37
46
  rdoc_options:
38
- - --inline-source
39
47
  - --charset=UTF-8
40
48
  require_paths:
41
49
  - lib
@@ -54,9 +62,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
62
  requirements: []
55
63
 
56
64
  rubyforge_project:
57
- rubygems_version: 1.2.0
65
+ rubygems_version: 1.3.5
58
66
  signing_key:
59
- specification_version: 2
67
+ specification_version: 3
60
68
  summary: selectable_attr generates extra methods dynamically
61
- test_files: []
62
-
69
+ test_files:
70
+ - spec/selectable_attr_base_alias_spec.rb
71
+ - spec/selectable_attr_enum_spec.rb
72
+ - spec/spec_helper.rb