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 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