meta_field 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +119 -0
- data/Rakefile +38 -0
- data/lib/generators/meta_field/migration/migration_generator.rb +38 -0
- data/lib/generators/meta_field/migration/templates/active_record/migration.rb +42 -0
- data/lib/meta_field.rb +6 -0
- data/lib/meta_field/extension.rb +174 -0
- data/lib/meta_field/meta.rb +4 -0
- data/lib/meta_field/proxy.rb +24 -0
- data/lib/meta_field/railtie.rb +10 -0
- data/lib/meta_field/version.rb +3 -0
- data/lib/tasks/meta_field_tasks.rake +4 -0
- metadata +73 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
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.rdoc
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
= MetaField
|
2
|
+
|
3
|
+
Author:: Yuichi Takeuchi uzuki05@takeyu-web.com
|
4
|
+
Website:: http://takeyu-web.com/
|
5
|
+
Copyright:: Copyright 2012 Yuichi Takeuchi
|
6
|
+
License:: MIT-LICENSE.
|
7
|
+
|
8
|
+
もっと柔軟にメタデータを付けたい。いちいちカラムを増やしたくない。
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
|
12
|
+
# your Gemfile
|
13
|
+
gem 'meta_field'
|
14
|
+
|
15
|
+
=== Post Instration
|
16
|
+
|
17
|
+
$ rails g meta_field:migration
|
18
|
+
$ rake db:migrate
|
19
|
+
|
20
|
+
== Usage
|
21
|
+
|
22
|
+
=== メタ属性の定義
|
23
|
+
|
24
|
+
モデルクラスで meta_field を宣言します。
|
25
|
+
|
26
|
+
class Book < ActiveRecord::Base
|
27
|
+
meta_field :released_at, :datetime
|
28
|
+
meta_attr :page, :integer, index: false # meta_attr は meta_field の別名
|
29
|
+
meta_field :note, :text, default: '(none)'
|
30
|
+
end
|
31
|
+
|
32
|
+
STIを使うこともできます。親のメタ属性は子でも使用できます。
|
33
|
+
|
34
|
+
class Animal < ActiveRecord::Base
|
35
|
+
meta_field :name, :string
|
36
|
+
end
|
37
|
+
|
38
|
+
class Dog < Animal
|
39
|
+
meta_field :pedigree
|
40
|
+
end
|
41
|
+
|
42
|
+
class Cat < Animal
|
43
|
+
end
|
44
|
+
|
45
|
+
=== メタ属性の使用
|
46
|
+
|
47
|
+
宣言した属性名のsetter/getterが提供されます。
|
48
|
+
|
49
|
+
animal.name #=> nil
|
50
|
+
animal.name = "Pochi"
|
51
|
+
animal.name #=> "Pochi"
|
52
|
+
animal.save
|
53
|
+
Animal.find(animal.id).name #=> "Pochi"
|
54
|
+
|
55
|
+
=== メタ属性による検索
|
56
|
+
|
57
|
+
meta_joinスコープを利用できます。
|
58
|
+
|
59
|
+
meta_joinを使うと、メタ属性を使って検索したり並び替えたりするためのサブクエリがJOINされます。
|
60
|
+
|
61
|
+
# released_atの降順でソート
|
62
|
+
Book.meta_join(:released_at).order('released_at DESC')
|
63
|
+
|
64
|
+
# priceの昇順、同一の場合はreleased_atの降順でソート
|
65
|
+
Book.meta_join(:released_at, :price).order('price ASC, released_at DESC')
|
66
|
+
|
67
|
+
# priceで検索
|
68
|
+
Book.meta_join(:price).where(Arel.sql('price BETWEEN 1000 AND 2000')).order('price ASC')
|
69
|
+
# メタ属性でない通常の属性と組み合わせた検索もできます。
|
70
|
+
Book.meta_join(:price).where(t.arel_table[:hoge].matches('%HOGE%').and(Arel.sql('price BETWEEN 1000 AND 2000'))).order('price ASC')
|
71
|
+
|
72
|
+
JOIN対象を少なくするために、JOINの前に検索しておきたい場合は、 .meta_join に、属性名をキーに、検索条件を値とするハッシュを渡します。
|
73
|
+
|
74
|
+
# released_atが1年前より新しものを検索しからJOINし、価格の昇順でソート
|
75
|
+
Book.meta_join(:released_at: Book.meta[:released_at].gt(1.years.ago)).meta_join(:price).order(:price)
|
76
|
+
# または、検索条件無し=nilとして
|
77
|
+
Book.meta_join(:released_at: Book.meta[:released_at].gt(1.years.ago), price: nil).order(:price)
|
78
|
+
|
79
|
+
.meta[:released_at] は、メタ属性で検索を行う場合に、そのままではメタ属性の型毎に別々のカラムに入っていたり非常に扱いにくいため、これを緩和するプロキシオブジェクトを返します。
|
80
|
+
.meta_join内で、Arelを使った条件組み立てを行う際に、.arel_table[:hoge]と同じ感じで使用します。
|
81
|
+
|
82
|
+
|
83
|
+
== 関連先モデルのメタ属性による検索
|
84
|
+
|
85
|
+
サブクエリのJOINを使用して下さい。
|
86
|
+
|
87
|
+
# 21歳から39歳の著者の本を出版日の降順で取り出す
|
88
|
+
# 「21歳から39歳の著者」を検索するサブクエリ組み立て
|
89
|
+
books_table = Book.arel_table
|
90
|
+
selected_authors_table = Author.meta_join(age: Author.meta[:age].gt(20).and(Author.meta[:age].lt(40))).arel.as('selected_authors')
|
91
|
+
# JOINして、「出版日の降順」のSQLを組み立てる
|
92
|
+
sql = Book.meta_join(:released_at).arel
|
93
|
+
.join(selected_authors_table, Arel::Nodes::InnerJoin)
|
94
|
+
.on(books_table[:author_id].eq(selected_authors_table[:id]))
|
95
|
+
.order('released_at DESC').to_sql
|
96
|
+
# 検索実行
|
97
|
+
books = Book.find_by_sql(sql)
|
98
|
+
|
99
|
+
|
100
|
+
== インデックスの使用
|
101
|
+
|
102
|
+
検索のためのINDEXは、デフォルトで値に対して使用されます。(:text / :binary を除く)
|
103
|
+
検索が不要なメタ属性は index: false とすることで、明示的にインデックスの使用をキャンセルできます。
|
104
|
+
|
105
|
+
|
106
|
+
== 型などの変更
|
107
|
+
|
108
|
+
型ごとに別々のカラムにデータが格納されるため、途中から型を変更すると、変更前の値を取得できなくなります。(未設定扱いになります)
|
109
|
+
|
110
|
+
インデックスを使用する属性と使用しない属性では、利用されるカラムが異なるため、途中からインデックスの使用・不使用を変更した場合も同様です。
|
111
|
+
|
112
|
+
|
113
|
+
== 注意
|
114
|
+
|
115
|
+
- 仕様変更があっても泣かない。
|
116
|
+
|
117
|
+
- バグっても泣かない。
|
118
|
+
|
119
|
+
- 何が起きても責任はとれません。
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'MetaField'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module MetaField
|
5
|
+
class MigrationGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
desc "Generates migration for MetaField models"
|
9
|
+
|
10
|
+
def self.orm
|
11
|
+
Rails::Generators.options[:rails][:orm]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.source_root
|
15
|
+
File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.orm_has_migration?
|
19
|
+
[:active_record].include? orm
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.next_migration_number(dirname)
|
23
|
+
if ActiveRecord::Base.timestamped_migrations
|
24
|
+
migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
25
|
+
migration_number += 1
|
26
|
+
migration_number.to_s
|
27
|
+
else
|
28
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_migration_file
|
33
|
+
if self.class.orm_has_migration?
|
34
|
+
migration_template 'migration.rb', 'db/migrate/meta_field_migration'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class MetaFieldMigration < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :meta_field_metas do |t|
|
4
|
+
t.integer :obj_id
|
5
|
+
t.string :obj_type
|
6
|
+
t.string :basename
|
7
|
+
|
8
|
+
t.string :string
|
9
|
+
t.text :text
|
10
|
+
t.integer :integer
|
11
|
+
t.float :float
|
12
|
+
t.decimal :decimal
|
13
|
+
t.datetime :datetime
|
14
|
+
t.timestamp :timestamp
|
15
|
+
t.time :time
|
16
|
+
t.date :date
|
17
|
+
t.binary :binary
|
18
|
+
t.boolean :boolean
|
19
|
+
t.string :indexed_string
|
20
|
+
t.integer :indexed_integer
|
21
|
+
t.float :indexed_float
|
22
|
+
t.decimal :indexed_decimal
|
23
|
+
t.datetime :indexed_datetime
|
24
|
+
t.timestamp :indexed_timestamp
|
25
|
+
t.time :indexed_time
|
26
|
+
t.date :indexed_date
|
27
|
+
t.boolean :indexed_boolean
|
28
|
+
end
|
29
|
+
add_index :meta_field_metas, [:obj_id, :obj_type]
|
30
|
+
add_index :meta_field_metas, [:obj_id, :obj_type, :basename]
|
31
|
+
|
32
|
+
add_index :meta_field_metas, :indexed_string
|
33
|
+
add_index :meta_field_metas, :indexed_integer
|
34
|
+
add_index :meta_field_metas, :indexed_float
|
35
|
+
add_index :meta_field_metas, :indexed_decimal
|
36
|
+
add_index :meta_field_metas, :indexed_datetime
|
37
|
+
add_index :meta_field_metas, :indexed_timestamp
|
38
|
+
add_index :meta_field_metas, :indexed_time
|
39
|
+
add_index :meta_field_metas, :indexed_date
|
40
|
+
add_index :meta_field_metas, :indexed_boolean
|
41
|
+
end
|
42
|
+
end
|
data/lib/meta_field.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'meta_field/proxy'
|
3
|
+
|
4
|
+
module MetaField
|
5
|
+
module Extension
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class << self
|
10
|
+
def inherited_with_meta_field(klass) #:nodoc:
|
11
|
+
inherited_without_meta_field klass
|
12
|
+
if klass != MetaField::Meta
|
13
|
+
klass.class_eval do
|
14
|
+
scope :meta_join, ->(*args){ _meta_join(*args) }
|
15
|
+
end
|
16
|
+
klass.send(:include, MetaField::ModelExtension) if klass.superclass == ActiveRecord::Base
|
17
|
+
end
|
18
|
+
end
|
19
|
+
alias_method_chain :inherited, :meta_field
|
20
|
+
end
|
21
|
+
|
22
|
+
descendants.each do |klass|
|
23
|
+
if klass != MetaField::Meta
|
24
|
+
klass.class_eval do
|
25
|
+
scope :meta_join, ->(*args){ _meta_join(*args) }
|
26
|
+
end
|
27
|
+
klass.send(:include, MetaField::ModelExtension) if klass.superclass == ActiveRecord::Base
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ModelExtension
|
35
|
+
extend ActiveSupport::Concern
|
36
|
+
|
37
|
+
included do
|
38
|
+
after_save :save_meta_metas
|
39
|
+
|
40
|
+
has_many :metafield_metas, class_name: 'MetaField::Meta', as: :obj, dependent: :destroy
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
# メタ属性を検索・ソートに使うためにJOIN
|
45
|
+
#
|
46
|
+
# # released_atの降順でソート
|
47
|
+
# Book.meta_join(:released_at).order('released_at DESC')
|
48
|
+
#
|
49
|
+
# # priceの昇順、同一の場合はreleased_atの降順でソート
|
50
|
+
# Book.meta_join(:released_at, :price).order('price ASC, released_at DESC')
|
51
|
+
#
|
52
|
+
# # released_atが1年前より新しものを検索し、価格の昇順でソート
|
53
|
+
# Book.meta_join(:released_at: Book.meta[:released_at].gt(1.years.ago), price: nil).order(:price)
|
54
|
+
#
|
55
|
+
# scope ではSTIに対応できなかったのでscopeはinheritedで全クラスで定義し、クラスメソッドを呼ぶ形で対処
|
56
|
+
# scope :meta_join, ->(*args) do
|
57
|
+
def _meta_join(*args)
|
58
|
+
basenames = {}
|
59
|
+
case args.size
|
60
|
+
when 1
|
61
|
+
case args[0]
|
62
|
+
when Hash
|
63
|
+
basenames = args[0].dup
|
64
|
+
else
|
65
|
+
basenames[args[0]] = nil
|
66
|
+
end
|
67
|
+
else
|
68
|
+
args.each{|arg| basenames[arg] = nil }
|
69
|
+
end
|
70
|
+
query = scoped
|
71
|
+
basenames.each{ |basename, where_cond|
|
72
|
+
quoted_basename = connection.quote_string(basename.to_s)
|
73
|
+
sub = MetaField::Meta.arel_table
|
74
|
+
sub = sub.where(sub[:basename].eq(basename))
|
75
|
+
sub = sub.where(where_cond) if where_cond
|
76
|
+
sub = sub.project(Arel.sql("#{connection.quote_column_name('obj_id')} as #{ connection.quote_column_name(quoted_basename+'_obj_id') }, #{connection.quote_column_name(meta_fields[basename.to_sym][0])} as #{connection.quote_column_name(quoted_basename)}"))
|
77
|
+
query = query.joins("INNER JOIN (#{ sub.to_sql }) ON #{connection.quote_table_name(table_name)}.#{connection.quote_column_name('id')} = #{connection.quote_column_name(quoted_basename+'_obj_id')}")
|
78
|
+
}
|
79
|
+
query
|
80
|
+
end
|
81
|
+
private :_meta_join
|
82
|
+
|
83
|
+
def meta_fields
|
84
|
+
return @meta_fields if @meta_fields
|
85
|
+
ancestors_meta_fields = self.superclass == ActiveRecord::Base ? {} : self.superclass.meta_fields
|
86
|
+
@meta_fields = Marshal.load(Marshal.dump(ancestors_meta_fields))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
module ClassMethods
|
93
|
+
# メタ属性を追加する
|
94
|
+
#
|
95
|
+
# class Book < ActiveRecord::Base
|
96
|
+
# attr_accessible :name, :released_at, :subtitle, :note
|
97
|
+
# meta_field :released_at, :datetime
|
98
|
+
# meta_field :subtitle, :string
|
99
|
+
# meta_field :page, :integer, index: false
|
100
|
+
# meta_field :note, :text, default: '特記事項無し'
|
101
|
+
# end
|
102
|
+
def meta_field(basename, datatype, meta_options = nil)
|
103
|
+
meta_options = {index: true}.merge(meta_options || {})
|
104
|
+
meta_options[:index] = false if [:text, :binary].include?(datatype.to_sym)
|
105
|
+
datatype = "indexed_#{datatype}" if meta_options[:index]
|
106
|
+
meta_fields[basename.to_sym] = [datatype.to_sym, meta_options]
|
107
|
+
class_eval <<CODE
|
108
|
+
def #{basename}_record
|
109
|
+
unless @attributes_cache[:#{basename}_record]
|
110
|
+
query = metafield_metas.where(basename: #{basename.to_s.inspect})
|
111
|
+
unless obj = query.first
|
112
|
+
obj = query.build
|
113
|
+
obj.#{datatype} = self.class.meta_fields[:#{basename}][1][:default]
|
114
|
+
end
|
115
|
+
@attributes_cache[:#{basename}_record] = obj
|
116
|
+
end
|
117
|
+
@attributes_cache[:#{basename}_record]
|
118
|
+
end
|
119
|
+
private :#{basename}_record
|
120
|
+
|
121
|
+
def #{basename}
|
122
|
+
#{basename}_record.#{datatype}
|
123
|
+
end
|
124
|
+
|
125
|
+
def #{basename}=(value)
|
126
|
+
#{basename}_record.#{datatype} = value
|
127
|
+
end
|
128
|
+
CODE
|
129
|
+
end
|
130
|
+
alias :meta_attr :meta_field
|
131
|
+
alias :meta_column :meta_field
|
132
|
+
|
133
|
+
|
134
|
+
# meta_join でメタ属性での絞り込みを行う際にArelっぽく標記するために使うProxyを得る
|
135
|
+
# メタ属性は単純なカラム名で扱うことができないため、Proxyを通して操作する
|
136
|
+
#
|
137
|
+
# Book.meta_join(:subtitle: Book.meta[:subtitle].matches_any(['%KEYWORD1%', '%KEYWORD2%']))
|
138
|
+
# # => SELECT "books".*
|
139
|
+
# # FROM "books" INNER JOIN (
|
140
|
+
# # SELECT "obj_id" as "note_obj_id", "text" as "note"
|
141
|
+
# # FROM "meta_field_metas"
|
142
|
+
# # WHERE
|
143
|
+
# # "meta_field_metas"."obj_type" = 'Book' AND "meta_field_metas"."basename" = 'note' AND
|
144
|
+
# # ("meta_field_metas"."text" LIKE '%HOGE%' OR "meta_field_metas"."text" LIKE '%FUGA%')
|
145
|
+
# # ) ON "books"."id" = "note_obj_id"
|
146
|
+
#
|
147
|
+
#
|
148
|
+
# Author.meta_join(:age: Author.meta[:age].gt(20).and(Author.meta[:age].lt(40))).order(:age)
|
149
|
+
# # => SELECT "authors".*
|
150
|
+
# # FROM "authors" INNER JOIN (
|
151
|
+
# # SELECT "obj_id" as "age_obj_id", "integer" as "age"
|
152
|
+
# # FROM "meta_field_metas"
|
153
|
+
# # WHERE
|
154
|
+
# # "meta_field_metas"."obj_type" = 'Author' AND "meta_field_metas"."basename" = 'age AND
|
155
|
+
# # "meta_field_metas"."integer" > 20 AND "meta_field_metas"."integer" < 40
|
156
|
+
# # ) ON "authors"."id" = "age_obj_id"
|
157
|
+
# # ORDER BY age
|
158
|
+
|
159
|
+
def meta
|
160
|
+
MetaField::MetaProxy.new(self)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def save_meta_metas
|
165
|
+
self.class.meta_fields.keys.each do |basename|
|
166
|
+
meta_record = send("#{basename}_record")
|
167
|
+
meta_record.obj ||= self
|
168
|
+
meta_record.save
|
169
|
+
end
|
170
|
+
end
|
171
|
+
private :save_meta_metas
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MetaField
|
2
|
+
class MetaProxy
|
3
|
+
def initialize(klass)
|
4
|
+
@klass = klass
|
5
|
+
@type = klass.base_class.to_s
|
6
|
+
end
|
7
|
+
def [](basename)
|
8
|
+
t = MetaField::Meta.arel_table
|
9
|
+
NodeProxy.new(@klass.meta_fields[basename.to_sym][0], t[:obj_type].eq(@type).and(t[:basename].eq(basename.to_s)))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class NodeProxy
|
14
|
+
def initialize(datatype, obj)
|
15
|
+
@datatype = datatype
|
16
|
+
@obj = obj
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(action, *args)
|
20
|
+
@obj.and(MetaField::Meta.arel_table[@datatype].send(action, *args))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meta_field
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Yuichi Takeuchi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.0
|
30
|
+
description: ActiveRecord meta_field for Rails 3
|
31
|
+
email:
|
32
|
+
- uzuki05@takeyu-web.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- lib/tasks/meta_field_tasks.rake
|
38
|
+
- lib/meta_field/railtie.rb
|
39
|
+
- lib/meta_field/proxy.rb
|
40
|
+
- lib/meta_field/extension.rb
|
41
|
+
- lib/meta_field/version.rb
|
42
|
+
- lib/meta_field/meta.rb
|
43
|
+
- lib/meta_field.rb
|
44
|
+
- lib/generators/meta_field/migration/templates/active_record/migration.rb
|
45
|
+
- lib/generators/meta_field/migration/migration_generator.rb
|
46
|
+
- MIT-LICENSE
|
47
|
+
- Rakefile
|
48
|
+
- README.rdoc
|
49
|
+
homepage: http://takeyu-web.com/
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.23
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: ActiveRecord meta_field for Rails 3
|
73
|
+
test_files: []
|