activerecord-bixformer 0.2.6 → 0.3.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.
- 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
|