activerecord-bixformer 0.2.6 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README-ja.md +14 -8
- data/lib/activerecord-bixformer/autoload.rb +1 -0
- data/lib/activerecord-bixformer/model/base.rb +25 -18
- data/lib/activerecord-bixformer/model/csv/base.rb +31 -15
- data/lib/activerecord-bixformer/model_callback.rb +92 -0
- data/lib/activerecord-bixformer/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd4ea598a0c120a784bbeb9f5a296471a5385f57
|
4
|
+
data.tar.gz: 7078cc54cd2675e0081362d897ee7ff74985b2c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 868cd4eba053a212776bb8c5b1ea4b1c25d0da8c5dcddd5f0e48cd302e13db17bd4ed4d497f4b9f157544de472d22b46a3462ae97b814fa16a8d69f6cc8f2f20
|
7
|
+
data.tar.gz: 2856bb8d614bbd9e64bbf6c4bd47d85e7c064123d0603dec9d236478580dd93b30225e8cbc25d6c327fc98f402e269592ebadc4863dcaf5d432a4ae345d3d00a
|
data/README-ja.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
以下のような特徴があります。
|
6
6
|
|
7
7
|
* `accepts_nested_attributes_for` で定義された関連モデルを同時に扱える
|
8
|
-
*
|
8
|
+
* インポート時、インポートデータが正当な値かどうかをチェックする
|
9
9
|
* 設定用クラスを定義して使い、モデル、属性単位で処理をカスタマイズ可能
|
10
10
|
|
11
11
|
現在のところ、インポート/エクスポート可能なデータ形式は
|
@@ -124,7 +124,9 @@ class SamplePlan
|
|
124
124
|
# - 配列を返すProcオブジェクトかメソッド名/シンボルで指定
|
125
125
|
# - 有効な値については、「インポート時に有効な値」を参照
|
126
126
|
#
|
127
|
-
bixformer_preferred_skip_attributes
|
127
|
+
bixformer_preferred_skip_attributes :skippable_attributes
|
128
|
+
|
129
|
+
def skippable_attributes
|
128
130
|
[
|
129
131
|
# ルートの要素は、対象モデル(上の例なら user )への指定
|
130
132
|
# bixformer_entry で定義されている属性で指定
|
@@ -242,13 +244,13 @@ class SamplePlan
|
|
242
244
|
scope: :bixformer,
|
243
245
|
|
244
246
|
# translation を検索するスコープを、基点のスコープ配下に増やしたい場合に指定
|
245
|
-
extend_scopes: [:
|
247
|
+
extend_scopes: [:version2, :version1]
|
246
248
|
|
247
249
|
# 上記の場合、ユーザが投稿したタイトルは
|
248
250
|
#
|
249
|
-
# bixformer.version2.user/posts.title
|
250
|
-
# bixformer.version1.user/posts.title
|
251
|
-
# bixformer.user/posts.title
|
251
|
+
# bixformer.version2.attributes.user/posts.title
|
252
|
+
# bixformer.version1.attributes.user/posts.title
|
253
|
+
# bixformer.attributes.user/posts.title
|
252
254
|
#
|
253
255
|
# の順で検索され、最初に見つかった translation を実行します
|
254
256
|
|
@@ -317,7 +319,9 @@ end
|
|
317
319
|
|
318
320
|
### 本フレームワークに定義されたModel一覧
|
319
321
|
|
320
|
-
|
322
|
+
Model は各データ形式毎に異なる処理が必要になるため、データ形式毎に使えるクラスが異なります。
|
323
|
+
|
324
|
+
#### CSV
|
321
325
|
|
322
326
|
* base
|
323
327
|
* has_one な関連モデル用。 has_many な関連モデルには使えない
|
@@ -329,6 +333,8 @@ end
|
|
329
333
|
|
330
334
|
### 本フレームワークに定義されたAttribute一覧
|
331
335
|
|
336
|
+
Attribute は、基本的にデータ形式に依らず、使用可能な想定をしています。
|
337
|
+
|
332
338
|
* string
|
333
339
|
* エクスポートでは `to_s` し、インポートでは `strip` して `presence` する
|
334
340
|
* boolean
|
@@ -349,7 +355,7 @@ end
|
|
349
355
|
* override
|
350
356
|
* モデルに処理を委譲する
|
351
357
|
* モデルに `override_import_属性名` / `override_export_属性名` を定義すること
|
352
|
-
* インポートでは、インポートデータ、エクスポートでは、 ActiveRecord
|
358
|
+
* インポートでは、インポートデータ、エクスポートでは、 ActiveRecord のインスタンスが引数となる
|
353
359
|
* インポート/エクスポートする値を返すこと
|
354
360
|
|
355
361
|
### インポート時に有効な値
|
@@ -5,6 +5,7 @@ module ActiveRecord
|
|
5
5
|
autoload :ImportValueValidatable, 'activerecord-bixformer/import_value_validatable'
|
6
6
|
autoload :Plan, 'activerecord-bixformer/plan'
|
7
7
|
autoload :PlanAccessor, 'activerecord-bixformer/plan_accessor'
|
8
|
+
autoload :ModelCallback, 'activerecord-bixformer/model_callback'
|
8
9
|
|
9
10
|
module Attribute
|
10
11
|
autoload :Base, 'activerecord-bixformer/attribute/base'
|
@@ -12,10 +12,9 @@ module ActiveRecord
|
|
12
12
|
# @attr_reader [Hash<String, ActiveRecord::Bixformer::Model::Base>] associations
|
13
13
|
# the import/export target association names and its instance.
|
14
14
|
# @attr_reader [ActiveRecord::Bixformer::Translator::I18n] translator
|
15
|
-
# @attr_reader [ActiveRecord::Bixformer::Plan::Base] plan
|
16
|
-
# active plan in the import/export process.
|
17
15
|
class Base
|
18
16
|
include ::ActiveRecord::Bixformer::ImportValueValidatable
|
17
|
+
include ::ActiveRecord::Bixformer::ModelCallback
|
19
18
|
|
20
19
|
attr_reader :name, :options, :parent, :attributes, :associations,
|
21
20
|
:preferred_skip_attributes, :translator
|
@@ -92,14 +91,18 @@ module ActiveRecord
|
|
92
91
|
values = {}.with_indifferent_access
|
93
92
|
normalizer = ::ActiveRecord::Bixformer::AssignableAttributesNormalizer.new(plan, self, parent_record_id)
|
94
93
|
|
95
|
-
|
96
|
-
|
94
|
+
run_callback :import, type: :attribute do
|
95
|
+
@attributes.each do |attr|
|
96
|
+
attribute_value = run_callback :import, on: attr.name do
|
97
|
+
block.call(attr)
|
98
|
+
end
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
|
100
|
+
# 取り込み時は、 preferred_skip な属性では、有効でない値は取り込まない
|
101
|
+
next if ! presence_value?(attribute_value) &&
|
102
|
+
@preferred_skip_attributes.include?(attr.name.to_s)
|
101
103
|
|
102
|
-
|
104
|
+
values[attr.name] = attribute_value
|
105
|
+
end
|
103
106
|
end
|
104
107
|
|
105
108
|
# データの検証と正規化
|
@@ -120,19 +123,23 @@ module ActiveRecord
|
|
120
123
|
def make_each_association_import_value(values, &block)
|
121
124
|
self_record_id = values[activerecord_constant.primary_key]
|
122
125
|
|
123
|
-
|
124
|
-
|
126
|
+
run_callback :import, type: :association do
|
127
|
+
@associations.each do |association|
|
128
|
+
association_value = run_callback :import, on: association.name do
|
129
|
+
block.call(association, self_record_id)
|
130
|
+
end
|
125
131
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
132
|
+
if association_value.is_a?(::Array)
|
133
|
+
# has_many な場合は、配列が返ってくるが、空と思われる要素は結果に含めない
|
134
|
+
association_value = association_value.reject { |v| ! presence_value?(v) }
|
135
|
+
end
|
130
136
|
|
131
|
-
|
132
|
-
|
133
|
-
|
137
|
+
# 取り込み時は、 preferred_skip な関連では、有効でない値は取り込まない
|
138
|
+
next if ! presence_value?(association_value) &&
|
139
|
+
@preferred_skip_attributes.include?(association.name.to_s)
|
134
140
|
|
135
|
-
|
141
|
+
values["#{association.name}_attributes".to_sym] = association_value
|
142
|
+
end
|
136
143
|
end
|
137
144
|
|
138
145
|
values
|
@@ -4,31 +4,47 @@ module ActiveRecord
|
|
4
4
|
module Csv
|
5
5
|
class Base < ::ActiveRecord::Bixformer::Model::Base
|
6
6
|
def export(record_or_records)
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
run_callback :export do
|
8
|
+
values = run_callback :export, type: :attribute do
|
9
|
+
# has_one でしか使わない想定なので record_or_records は ActiveRecord::Base のはず
|
10
|
+
@attributes.map do |attr|
|
11
|
+
attribute_value = if record_or_records
|
12
|
+
run_callback :export, on: attr.name do
|
13
|
+
attr.export(record_or_records)
|
14
|
+
end
|
15
|
+
end
|
10
16
|
|
11
|
-
|
12
|
-
|
17
|
+
[csv_title(attr.name), attribute_value]
|
18
|
+
end.to_h.with_indifferent_access
|
19
|
+
end
|
13
20
|
|
14
|
-
|
15
|
-
|
21
|
+
run_callback :export, type: :association do
|
22
|
+
@associations.inject(values) do |each_values, association|
|
23
|
+
association_value = if record_or_records
|
24
|
+
run_callback :export, on: association.name do
|
25
|
+
record_or_records.__send__(association.name)
|
26
|
+
end
|
27
|
+
end
|
16
28
|
|
17
|
-
|
29
|
+
association_value = association_value.to_a if association_value.is_a?(::ActiveRecord::Relation)
|
18
30
|
|
19
|
-
|
31
|
+
each_values.merge(association.export(association_value))
|
32
|
+
end
|
33
|
+
end
|
20
34
|
end
|
21
35
|
end
|
22
36
|
|
23
37
|
def import(csv_body_row, parent_record_id = nil)
|
24
|
-
|
25
|
-
|
38
|
+
run_callback :import do
|
39
|
+
values = make_each_attribute_import_value(parent_record_id) do |attr|
|
40
|
+
csv_value = csv_body_row[csv_title(attr.name)]
|
26
41
|
|
27
|
-
|
28
|
-
|
42
|
+
attr.import(csv_value)
|
43
|
+
end
|
29
44
|
|
30
|
-
|
31
|
-
|
45
|
+
make_each_association_import_value(values) do |association, self_record_id|
|
46
|
+
association.import(csv_body_row, self_record_id)
|
47
|
+
end
|
32
48
|
end
|
33
49
|
end
|
34
50
|
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Bixformer
|
3
|
+
module ModelCallback
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :__bixformer_export_callbacks
|
8
|
+
class_attribute :__bixformer_import_callbacks
|
9
|
+
|
10
|
+
self.__bixformer_export_callbacks = {}
|
11
|
+
self.__bixformer_import_callbacks = {}
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def self.callback_store_key(options)
|
16
|
+
if options[:on]
|
17
|
+
"on:#{options[:on]}"
|
18
|
+
elsif options[:type]
|
19
|
+
"type:#{options[:type]}"
|
20
|
+
else
|
21
|
+
"global"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
[:export, :import].each do |target|
|
28
|
+
[:before, :around, :after].each do |timing|
|
29
|
+
define_method "bixformer_#{timing}_#{target}" do |*callback, &block|
|
30
|
+
callback_store = self.__send__("__bixformer_#{target}_callbacks")[timing] ||= {}
|
31
|
+
|
32
|
+
options = callback.extract_options!.with_indifferent_access
|
33
|
+
key = callback_store_key(options)
|
34
|
+
|
35
|
+
callback_store[key] = options.merge(
|
36
|
+
body: block ? block : options[:body] || callback.first
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def run_callback(target, options = {}, &body)
|
46
|
+
options = options.with_indifferent_access
|
47
|
+
|
48
|
+
before_callback = callback(target, :before, options)
|
49
|
+
if before_callback
|
50
|
+
return nil unless invoke_callback(before_callback)
|
51
|
+
end
|
52
|
+
|
53
|
+
around_callback = callback(target, :around, options)
|
54
|
+
result = invoke_callback(around_callback, &body)
|
55
|
+
|
56
|
+
after_callback = callback(target, :after, options)
|
57
|
+
invoke_callback(after_callback, args_required: true, args_value: result) if after_callback
|
58
|
+
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
def invoke_callback(callback, args_required: false, args_value: nil, &block)
|
63
|
+
if callback.is_a?(::Proc)
|
64
|
+
if block
|
65
|
+
self.instance_exec block, &callback
|
66
|
+
elsif args_required
|
67
|
+
self.instance_exec args_value, &callback
|
68
|
+
else
|
69
|
+
self.instance_exec &callback
|
70
|
+
end
|
71
|
+
elsif callback.is_a?(::Symbol) || callback.is_a?(::String)
|
72
|
+
if block
|
73
|
+
self.__send__(callback, &block)
|
74
|
+
elsif args_required
|
75
|
+
self.__send__(callback, args_value)
|
76
|
+
else
|
77
|
+
self.__send__(callback)
|
78
|
+
end
|
79
|
+
elsif block
|
80
|
+
yield block
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def callback(target, timing, options)
|
85
|
+
callback_store = self.__send__("__bixformer_#{target}_callbacks")[timing] || {}
|
86
|
+
callback_values = callback_store[self.class.callback_store_key(options)] || {}
|
87
|
+
|
88
|
+
callback_values[:body]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-bixformer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroaki Otsu
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -239,6 +239,7 @@ files:
|
|
239
239
|
- lib/activerecord-bixformer/model/base.rb
|
240
240
|
- lib/activerecord-bixformer/model/csv/base.rb
|
241
241
|
- lib/activerecord-bixformer/model/csv/indexed.rb
|
242
|
+
- lib/activerecord-bixformer/model_callback.rb
|
242
243
|
- lib/activerecord-bixformer/plan.rb
|
243
244
|
- lib/activerecord-bixformer/plan_accessor.rb
|
244
245
|
- lib/activerecord-bixformer/to/csv.rb
|