csv_row_model 0.3.10 → 0.4.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: c16a446fafcc7457fffac11919745acfa9f283cd
4
- data.tar.gz: ea6cdbed5009681cc3a8b92452f5b94bfc722640
3
+ metadata.gz: d13ce436eddba3a6cd5ad084cbd534098637279b
4
+ data.tar.gz: c0132db76eb2855b4fc0eddbe288a54e741e0544
5
5
  SHA512:
6
- metadata.gz: 6d3e8e9b72a3614bfe036917d2f724802ed8c1f9f42b0013273f761a6b9d850075ff52c2744c520b5a9159410fc99f9d87be15c12d4d614b9938feabf47c0dcf
7
- data.tar.gz: 49ab3a6bfbb1b34c293fb309b1f5cea4ea694ec667884ce39334e9d247dad7f51a867f728a1abe451c0b25f3de5a8d6625b2a602d35ba6e08d4afd9f5dd80d23
6
+ metadata.gz: 92c5b48c05ca65a73f997061a0db142b9cb684940b6adca4dee691d33b00b0bb115d4db05d6375da7e7b870c5334c667f95f4b7d5525d6c74c4eee44042d08a1
7
+ data.tar.gz: 4885e9fc4282bc8974ed6fe3f7db11c4f39875b142a0e0daca002341aff015c5f68d25017727072369592f6b6a7f50ad460c6d86cbdb7839dedad8bcf0442366
data/README.md CHANGED
@@ -8,8 +8,10 @@ First define your schema:
8
8
  class ProjectRowModel
9
9
  include CsvRowModel::Model
10
10
 
11
- column :id
11
+ column :id, options
12
12
  column :name
13
+
14
+ merge_options :id, more_options # optional
13
15
  end
14
16
  ```
15
17
 
@@ -4,10 +4,7 @@ module CsvRowModel
4
4
  module Concerns
5
5
  module InheritedClassVar
6
6
  extend ActiveSupport::Concern
7
-
8
- included do
9
- include InvalidOptions
10
- end
7
+ include InvalidOptions
11
8
 
12
9
  class_methods do
13
10
  # Clears the cache for a variable
@@ -1,39 +1,17 @@
1
+ require 'csv_row_model/export/base'
1
2
  require 'csv_row_model/export/dynamic_columns'
2
3
  require 'csv_row_model/export/attributes'
4
+ require 'csv_row_model/model/comparison'
3
5
 
4
6
  module CsvRowModel
5
7
  # Include this to with {Model} to have a RowModel for exporting to CSVs.
6
8
  module Export
7
9
  extend ActiveSupport::Concern
8
10
 
9
- included do
10
- include Attributes
11
- include DynamicColumns
11
+ include Base
12
+ include Attributes
13
+ include DynamicColumns
12
14
 
13
- attr_reader :source_model, :context
14
- validates :source_model, presence: true
15
- end
16
-
17
- # @param [Model] source_model object to export to CSV
18
- # @param [Hash] context
19
- def initialize(source_model, context={})
20
- @source_model = source_model
21
- @context = OpenStruct.new(context)
22
- end
23
-
24
- def to_rows
25
- [to_row]
26
- end
27
-
28
- # @return [Array] an array of public_send(column_name) of the CSV model
29
- def to_row
30
- formatted_attributes.values
31
- end
32
-
33
- class_methods do
34
- def setup(csv, context={}, with_headers: true)
35
- csv << headers(context) if with_headers
36
- end
37
- end
15
+ include Model::Comparison # can't be added on Model module because Model does not have attributes implemented
38
16
  end
39
17
  end
@@ -1,12 +1,9 @@
1
- require 'csv_row_model/model/comparison'
2
-
3
1
  module CsvRowModel
4
2
  module Export
5
3
  module Attributes
6
4
  extend ActiveSupport::Concern
7
5
 
8
6
  included do
9
- include Model::Comparison
10
7
  self.column_names.each { |*args| define_attribute_method(*args) }
11
8
  end
12
9
 
@@ -32,6 +29,14 @@ module CsvRowModel
32
29
  end
33
30
 
34
31
  class_methods do
32
+ # Safe to override. Method applied to each cell by default
33
+ #
34
+ # @param cell [Object] the cell's value
35
+ def format_cell(cell, column_name, column_index, context={})
36
+ cell
37
+ end
38
+
39
+ protected
35
40
  # See {Model#column}
36
41
  def column(column_name, options={})
37
42
  super
@@ -41,16 +46,8 @@ module CsvRowModel
41
46
  # Define default attribute method for a column
42
47
  # @param column_name [Symbol] the cell's column_name
43
48
  def define_attribute_method(column_name)
44
- define_method(column_name) do
45
- source_model.public_send(column_name)
46
- end
47
- end
48
-
49
- # Safe to override. Method applied to each cell by default
50
- #
51
- # @param cell [Object] the cell's value
52
- def format_cell(cell, column_name, column_index, context={})
53
- cell
49
+ return if method_defined? column_name
50
+ define_method(column_name) { source_model.public_send(column_name) }
54
51
  end
55
52
  end
56
53
  end
@@ -0,0 +1,34 @@
1
+ module CsvRowModel
2
+ module Export
3
+ module Base
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attr_reader :source_model, :context
8
+ validates :source_model, presence: true
9
+ end
10
+
11
+ # @param [Model] source_model object to export to CSV
12
+ # @param [Hash] context
13
+ def initialize(source_model, context={})
14
+ @source_model = source_model
15
+ @context = OpenStruct.new(context)
16
+ end
17
+
18
+ def to_rows
19
+ [to_row]
20
+ end
21
+
22
+ # @return [Array] an array of public_send(column_name) of the CSV model
23
+ def to_row
24
+ formatted_attributes.values
25
+ end
26
+
27
+ class_methods do
28
+ def setup(csv, context={}, with_headers: true)
29
+ csv << headers(context) if with_headers
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,148 +1,19 @@
1
+ require 'csv_row_model/import/base'
1
2
  require 'csv_row_model/import/attributes'
2
- require 'csv_row_model/import/presenter'
3
3
  require 'csv_row_model/import/dynamic_columns'
4
+ require 'csv_row_model/model/comparison'
4
5
 
5
6
  module CsvRowModel
6
7
  # Include this to with {Model} to have a RowModel for importing csvs.
7
8
  module Import
8
9
  extend ActiveSupport::Concern
9
10
 
10
- included do
11
- include Concerns::Inspect
12
- include Attributes
13
- include DynamicColumns
11
+ include Concerns::Inspect
14
12
 
15
- attr_reader :source_header, :source_row, :context, :index, :previous
13
+ include Base
14
+ include Attributes
15
+ include DynamicColumns
16
16
 
17
- self.column_names.each { |*args| define_attribute_method(*args) }
18
-
19
- validates :source_row, presence: true
20
- end
21
-
22
- # @param [Array] source_row the csv row
23
- # @param options [Hash]
24
- # @option options [Integer] :index index in the CSV file
25
- # @option options [Hash] :context extra data you want to work with the model
26
- # @option options [Array] :source_header the csv header row
27
- # @option options [CsvRowModel::Import] :previous the previous row model
28
- # @option options [CsvRowModel::Import] :parent if the instance is a child, pass the parent
29
- def initialize(source_row, options={})
30
- options = options.symbolize_keys.reverse_merge(context: {})
31
- @source_row, @context = source_row, OpenStruct.new(options[:context])
32
- @index, @source_header, @previous = options[:index], options[:source_header], options[:previous].try(:dup)
33
-
34
- previous.try(:free_previous)
35
- super(source_row, options)
36
- end
37
-
38
- # @return [Hash] a map of `column_name => source_row[index_of_column_name]`
39
- def mapped_row
40
- return {} unless source_row
41
- @mapped_row ||= self.class.column_names.zip(source_row).to_h
42
- end
43
-
44
- # Free `previous` from memory to avoid making a linked list
45
- def free_previous
46
- @previous = nil
47
- end
48
-
49
- # @return [Presenter] the presenter of self
50
- def presenter
51
- @presenter ||= self.class.presenter_class.new(self)
52
- end
53
-
54
- # @return [Model::CsvStringModel] a model with validations related to Model::csv_string_model (values are from format_cell)
55
- def csv_string_model
56
- @csv_string_model ||= begin
57
- if source_row
58
- column_names = self.class.column_names
59
- hash = column_names.zip(
60
- column_names.map.with_index do |column_name, index|
61
- self.class.format_cell(source_row[index], column_name, index, context)
62
- end
63
- ).to_h
64
- else
65
- hash = {}
66
- end
67
-
68
- self.class.csv_string_model_class.new(hash)
69
- end
70
- end
71
-
72
- # Safe to override.
73
- #
74
- # @return [Boolean] returns true, if this instance should be skipped
75
- def skip?
76
- !valid? || presenter.skip?
77
- end
78
-
79
- # Safe to override.
80
- #
81
- # @return [Boolean] returns true, if the entire csv file should stop reading
82
- def abort?
83
- presenter.abort?
84
- end
85
-
86
- def valid?(*args)
87
- super
88
-
89
- proc = -> do
90
- csv_string_model.valid?(*args)
91
- errors.messages.merge!(csv_string_model.errors.messages.reject {|k, v| v.empty? })
92
- errors.empty?
93
- end
94
-
95
- if using_warnings?
96
- csv_string_model.using_warnings(&proc)
97
- else
98
- proc.call
99
- end
100
- end
101
-
102
- class_methods do
103
- # See {Model#column}
104
- def column(column_name, options={})
105
- super
106
- define_attribute_method(column_name)
107
- end
108
-
109
- # @param [Import::Csv] csv to read from
110
- # @param [Hash] context extra data you want to work with the model
111
- # @param [Import] prevuous the previous row model
112
- # @return [Import] the next model instance from the csv
113
- def next(csv, source_header, context={}, previous=nil)
114
- csv.skip_header
115
- row_model = nil
116
-
117
- loop do # loop until the next parent or end_of_file? (need to read children rows)
118
- csv.read_row
119
- row_model ||= new(csv.current_row,
120
- index: csv.index,
121
- source_header: source_header,
122
- context: context,
123
- previous: previous)
124
-
125
- return row_model if csv.end_of_file?
126
-
127
- next_row_is_parent = !row_model.append_child(csv.next_row)
128
- return row_model if next_row_is_parent
129
- end
130
- end
131
-
132
- # @return [Class] the Class of the Presenter
133
- def presenter_class
134
- @presenter_class ||= inherited_custom_class(:presenter_class, Presenter)
135
- end
136
-
137
- protected
138
- def inspect_methods
139
- @inspect_methods ||= %i[mapped_row initialized_at parent context previous].freeze
140
- end
141
-
142
- # Call to define the presenter
143
- def presenter(&block)
144
- presenter_class.class_eval(&block)
145
- end
146
- end
17
+ include Model::Comparison # can't be added on Model module because Model does not have attributes implemented
147
18
  end
148
19
  end
@@ -1,5 +1,4 @@
1
1
  require 'csv_row_model/validators/boolean_format'
2
- require 'csv_row_model/model/comparison'
3
2
 
4
3
  module CsvRowModel
5
4
  module Import
@@ -7,7 +6,7 @@ module CsvRowModel
7
6
  extend ActiveSupport::Concern
8
7
 
9
8
  included do
10
- include Model::Comparison
9
+ self.column_names.each { |*args| define_attribute_method(*args) }
11
10
  end
12
11
 
13
12
  # Classes with a validations associated with them in csv_row_model/validators
@@ -90,9 +89,22 @@ module CsvRowModel
90
89
  end
91
90
 
92
91
  protected
92
+ # See {Model#column}
93
+ def column(column_name, options={})
94
+ super
95
+ define_attribute_method(column_name)
96
+ end
97
+
98
+ def merge_options(column_name, options={})
99
+ original_options = options(column_name)
100
+ add_type_validation(column_name) if !original_options[:validate_type] && options[:validate_type]
101
+ super
102
+ end
103
+
93
104
  # Define default attribute method for a column
94
105
  # @param column_name [Symbol] the cell's column_name
95
106
  def define_attribute_method(column_name)
107
+ return if method_defined? column_name
96
108
  add_type_validation(column_name)
97
109
  define_method(column_name) { original_attribute(column_name) }
98
110
  end
@@ -0,0 +1,136 @@
1
+ require 'csv_row_model/import/presenter'
2
+
3
+ module CsvRowModel
4
+ module Import
5
+ module Base
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :source_header, :source_row, :context, :index, :previous
10
+
11
+ validates :source_row, presence: true
12
+ end
13
+
14
+
15
+ # @param [Array] source_row the csv row
16
+ # @param options [Hash]
17
+ # @option options [Integer] :index index in the CSV file
18
+ # @option options [Hash] :context extra data you want to work with the model
19
+ # @option options [Array] :source_header the csv header row
20
+ # @option options [CsvRowModel::Import] :previous the previous row model
21
+ # @option options [CsvRowModel::Import] :parent if the instance is a child, pass the parent
22
+ def initialize(source_row, options={})
23
+ options = options.symbolize_keys.reverse_merge(context: {})
24
+ @source_row, @context = source_row, OpenStruct.new(options[:context])
25
+ @index, @source_header, @previous = options[:index], options[:source_header], options[:previous].try(:dup)
26
+
27
+ previous.try(:free_previous)
28
+ super(source_row, options)
29
+ end
30
+
31
+ # @return [Hash] a map of `column_name => source_row[index_of_column_name]`
32
+ def mapped_row
33
+ return {} unless source_row
34
+ @mapped_row ||= self.class.column_names.zip(source_row).to_h
35
+ end
36
+
37
+ # Free `previous` from memory to avoid making a linked list
38
+ def free_previous
39
+ @previous = nil
40
+ end
41
+
42
+ # @return [Presenter] the presenter of self
43
+ def presenter
44
+ @presenter ||= self.class.presenter_class.new(self)
45
+ end
46
+
47
+ # @return [Model::CsvStringModel] a model with validations related to Model::csv_string_model (values are from format_cell)
48
+ def csv_string_model
49
+ @csv_string_model ||= begin
50
+ if source_row
51
+ column_names = self.class.column_names
52
+ hash = column_names.zip(
53
+ column_names.map.with_index do |column_name, index|
54
+ self.class.format_cell(source_row[index], column_name, index, context)
55
+ end
56
+ ).to_h
57
+ else
58
+ hash = {}
59
+ end
60
+
61
+ self.class.csv_string_model_class.new(hash)
62
+ end
63
+ end
64
+
65
+ # Safe to override.
66
+ #
67
+ # @return [Boolean] returns true, if this instance should be skipped
68
+ def skip?
69
+ !valid? || presenter.skip?
70
+ end
71
+
72
+ # Safe to override.
73
+ #
74
+ # @return [Boolean] returns true, if the entire csv file should stop reading
75
+ def abort?
76
+ presenter.abort?
77
+ end
78
+
79
+ def valid?(*args)
80
+ super
81
+
82
+ proc = -> do
83
+ csv_string_model.valid?(*args)
84
+ errors.messages.merge!(csv_string_model.errors.messages.reject {|k, v| v.empty? })
85
+ errors.empty?
86
+ end
87
+
88
+ if using_warnings?
89
+ csv_string_model.using_warnings(&proc)
90
+ else
91
+ proc.call
92
+ end
93
+ end
94
+
95
+ class_methods do
96
+ # @param [Import::Csv] csv to read from
97
+ # @param [Hash] context extra data you want to work with the model
98
+ # @param [Import] prevuous the previous row model
99
+ # @return [Import] the next model instance from the csv
100
+ def next(csv, source_header, context={}, previous=nil)
101
+ csv.skip_header
102
+ row_model = nil
103
+
104
+ loop do # loop until the next parent or end_of_file? (need to read children rows)
105
+ csv.read_row
106
+ row_model ||= new(csv.current_row,
107
+ index: csv.index,
108
+ source_header: source_header,
109
+ context: context,
110
+ previous: previous)
111
+
112
+ return row_model if csv.end_of_file?
113
+
114
+ next_row_is_parent = !row_model.append_child(csv.next_row)
115
+ return row_model if next_row_is_parent
116
+ end
117
+ end
118
+
119
+ # @return [Class] the Class of the Presenter
120
+ def presenter_class
121
+ @presenter_class ||= inherited_custom_class(:presenter_class, Presenter)
122
+ end
123
+
124
+ protected
125
+ def inspect_methods
126
+ @inspect_methods ||= %i[mapped_row initialized_at parent context previous].freeze
127
+ end
128
+
129
+ # Call to define the presenter
130
+ def presenter(&block)
131
+ presenter_class.class_eval(&block)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -4,10 +4,10 @@ module CsvRowModel
4
4
  module Validations
5
5
  extend ActiveSupport::Concern
6
6
 
7
- included do
8
- include ActiveModel::Validations
9
- include Validators::ValidateAttributes
7
+ include ActiveModel::Validations
8
+ include Validators::ValidateAttributes
10
9
 
10
+ included do
11
11
  validate_attributes :csv
12
12
  end
13
13
 
@@ -1,5 +1,6 @@
1
1
  require 'csv_row_model/model/csv_string_model'
2
2
 
3
+ require 'csv_row_model/model/base'
3
4
  require 'csv_row_model/model/columns'
4
5
  require 'csv_row_model/model/children'
5
6
  require 'csv_row_model/model/dynamic_columns'
@@ -9,58 +10,15 @@ module CsvRowModel
9
10
  module Model
10
11
  extend ActiveSupport::Concern
11
12
 
12
- included do
13
- include Concerns::InheritedClassVar
13
+ include Concerns::InheritedClassVar
14
14
 
15
- include ActiveWarnings
16
- include Validators::ValidateAttributes
15
+ include ActiveWarnings
16
+ include Validators::ValidateAttributes
17
17
 
18
- include Columns
19
- include Children
20
- include DynamicColumns
18
+ include Base
21
19
 
22
- # @return [Model] return the parent, if this instance is a child
23
- attr_reader :parent
24
-
25
- # @return [DateTime] return when self has been intialized
26
- attr_reader :initialized_at
27
-
28
- validate_attributes :parent
29
- end
30
-
31
- # @param [NilClass] source not used here, see {Input}
32
- # @param [Hash] options
33
- # @option options [String] :parent if the instance is a child, pass the parent
34
- def initialize(source=nil, options={})
35
- @initialized_at = DateTime.now
36
- @parent = options[:parent]
37
- end
38
-
39
- # Safe to override.
40
- #
41
- # @return [Boolean] returns true, if this instance should be skipped
42
- def skip?
43
- !valid?
44
- end
45
-
46
- # Safe to override.
47
- #
48
- # @return [Boolean] returns true, if the entire csv file should stop reading
49
- def abort?
50
- false
51
- end
52
-
53
- class_methods do
54
- # @return [Class] the Class with validations of the csv_string_model
55
- def csv_string_model_class
56
- @csv_string_model_class ||= inherited_custom_class(:csv_string_model_class, CsvStringModel)
57
- end
58
-
59
- protected
60
- # Called to add validations to the csv_string_model_class
61
- def csv_string_model(&block)
62
- csv_string_model_class.class_eval(&block)
63
- end
64
- end
20
+ include Columns
21
+ include Children
22
+ include DynamicColumns
65
23
  end
66
24
  end
@@ -0,0 +1,52 @@
1
+ module CsvRowModel
2
+ module Model
3
+ module Base
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # @return [Model] return the parent, if this instance is a child
8
+ attr_reader :parent
9
+
10
+ # @return [DateTime] return when self has been intialized
11
+ attr_reader :initialized_at
12
+
13
+ validate_attributes :parent
14
+ end
15
+
16
+ # @param [NilClass] source not used here, see {Input}
17
+ # @param [Hash] options
18
+ # @option options [String] :parent if the instance is a child, pass the parent
19
+ def initialize(source=nil, options={})
20
+ @initialized_at = DateTime.now
21
+ @parent = options[:parent]
22
+ end
23
+
24
+ # Safe to override.
25
+ #
26
+ # @return [Boolean] returns true, if this instance should be skipped
27
+ def skip?
28
+ !valid?
29
+ end
30
+
31
+ # Safe to override.
32
+ #
33
+ # @return [Boolean] returns true, if the entire csv file should stop reading
34
+ def abort?
35
+ false
36
+ end
37
+
38
+ class_methods do
39
+ # @return [Class] the Class with validations of the csv_string_model
40
+ def csv_string_model_class
41
+ @csv_string_model_class ||= inherited_custom_class(:csv_string_model_class, CsvStringModel)
42
+ end
43
+
44
+ protected
45
+ # Called to add validations to the csv_string_model_class
46
+ def csv_string_model(&block)
47
+ csv_string_model_class.class_eval(&block)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -87,12 +87,18 @@ module CsvRowModel
87
87
  # @option options [String] :header human friendly string of the column name, by default format_header(column_name)
88
88
  # @option options [Hash] :header_matchs array with string to match cell to find in the row, by default column name
89
89
  def column(column_name, options={})
90
+ column_name = column_name.to_sym
91
+
90
92
  extra_keys = options.keys - VALID_OPTIONS_KEYS
91
93
  raise ArgumentError.new("invalid options #{extra_keys}") unless extra_keys.empty?
92
94
 
93
- merge_columns(column_name.to_sym => options)
95
+ merge_columns(column_name => options)
96
+ end
97
+
98
+ def merge_options(column_name, options={})
99
+ column_name = column_name.to_sym
100
+ column(column_name, (options(column_name) || {}).merge(options))
94
101
  end
95
- # alias_method :row, :column
96
102
  end
97
103
  end
98
104
  end
@@ -2,7 +2,6 @@ module CsvRowModel
2
2
  module Model
3
3
  module DynamicColumns
4
4
  extend ActiveSupport::Concern
5
-
6
5
  included do
7
6
  inherited_class_hash :dynamic_columns
8
7
  end
@@ -4,7 +4,6 @@ module CsvRowModel
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
-
8
7
  class << self
9
8
  alias_method :row_names, :column_names
10
9
  alias_method :rows, :columns
@@ -1,3 +1,3 @@
1
1
  module CsvRowModel
2
- VERSION = "0.3.10"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csv_row_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Chung
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-04-06 00:00:00.000000000 Z
12
+ date: 2016-04-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -66,11 +66,13 @@ files:
66
66
  - lib/csv_row_model/engine.rb
67
67
  - lib/csv_row_model/export.rb
68
68
  - lib/csv_row_model/export/attributes.rb
69
+ - lib/csv_row_model/export/base.rb
69
70
  - lib/csv_row_model/export/dynamic_columns.rb
70
71
  - lib/csv_row_model/export/file.rb
71
72
  - lib/csv_row_model/export/file_model.rb
72
73
  - lib/csv_row_model/import.rb
73
74
  - lib/csv_row_model/import/attributes.rb
75
+ - lib/csv_row_model/import/base.rb
74
76
  - lib/csv_row_model/import/csv.rb
75
77
  - lib/csv_row_model/import/dynamic_columns.rb
76
78
  - lib/csv_row_model/import/file.rb
@@ -79,6 +81,7 @@ files:
79
81
  - lib/csv_row_model/import/file_model.rb
80
82
  - lib/csv_row_model/import/presenter.rb
81
83
  - lib/csv_row_model/model.rb
84
+ - lib/csv_row_model/model/base.rb
82
85
  - lib/csv_row_model/model/children.rb
83
86
  - lib/csv_row_model/model/columns.rb
84
87
  - lib/csv_row_model/model/comparison.rb