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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0fefe763e939aad7ff7e50f2961962e24164a4d
4
- data.tar.gz: 435fbfa1250fa0f8cb11c6c1b97c678e0a808e02
3
+ metadata.gz: dd4ea598a0c120a784bbeb9f5a296471a5385f57
4
+ data.tar.gz: 7078cc54cd2675e0081362d897ee7ff74985b2c8
5
5
  SHA512:
6
- metadata.gz: bb7926a45c574069f491893edc80ece85d8a0782976bcb21bbd22d2f0b7b912d87c351bc7335d198c875bfa8576ba2dcb9d4ceab159a6cbda826734e529f0b6d
7
- data.tar.gz: f9bfe143d8be2fe6c0101f9703f3fe219ba4cc8cc239a108004a6687f5ba539a8d445644f91b88e6d5c297a8dbc64acd5810534e944116842acf7f53ee17f001
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
- * インポートデータに `primary_key` が含まれる場合、それが正当な値かどうかをチェックできる
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 -> do
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: [:version1, :version2]
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
- #### For CSV
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
- @attributes.each do |attr|
96
- attribute_value = block.call(attr)
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
- # 取り込み時は、 preferred_skip な属性では、有効でない値は取り込まない
99
- next if ! presence_value?(attribute_value) &&
100
- @preferred_skip_attributes.include?(attr.name.to_s)
100
+ # 取り込み時は、 preferred_skip な属性では、有効でない値は取り込まない
101
+ next if ! presence_value?(attribute_value) &&
102
+ @preferred_skip_attributes.include?(attr.name.to_s)
101
103
 
102
- values[attr.name] = attribute_value
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
- @associations.each do |association|
124
- association_value = block.call(association, self_record_id)
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
- if association_value.is_a?(::Array)
127
- # has_many な場合は、配列が返ってくるが、空と思われる要素は結果に含めない
128
- association_value = association_value.reject { |v| ! presence_value?(v) }
129
- end
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
- # 取り込み時は、 preferred_skip な関連では、有効でない値は取り込まない
132
- next if ! presence_value?(association_value) &&
133
- @preferred_skip_attributes.include?(association.name.to_s)
137
+ # 取り込み時は、 preferred_skip な関連では、有効でない値は取り込まない
138
+ next if ! presence_value?(association_value) &&
139
+ @preferred_skip_attributes.include?(association.name.to_s)
134
140
 
135
- values["#{association.name}_attributes".to_sym] = association_value
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
- # has_one でしか使わない想定なので record_or_records は ActiveRecord::Base のはず
8
- values = @attributes.map do |attr|
9
- attribute_value = record_or_records && attr.export(record_or_records)
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
- [csv_title(attr.name), attribute_value]
12
- end.to_h.with_indifferent_access
17
+ [csv_title(attr.name), attribute_value]
18
+ end.to_h.with_indifferent_access
19
+ end
13
20
 
14
- @associations.inject(values) do |each_values, association|
15
- association_value = record_or_records && record_or_records.__send__(association.name)
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
- association_value = association_value.to_a if association_value.is_a?(::ActiveRecord::Relation)
29
+ association_value = association_value.to_a if association_value.is_a?(::ActiveRecord::Relation)
18
30
 
19
- each_values.merge(association.export(association_value))
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
- values = make_each_attribute_import_value(parent_record_id) do |attr|
25
- csv_value = csv_body_row[csv_title(attr.name)]
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
- attr.import(csv_value)
28
- end
42
+ attr.import(csv_value)
43
+ end
29
44
 
30
- make_each_association_import_value(values) do |association, self_record_id|
31
- association.import(csv_body_row, self_record_id)
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
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Bixformer
3
- VERSION = "0.2.6"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  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.2.6
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-09-20 00:00:00.000000000 Z
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