bumblebee 3.0.1 → 3.1.0.pre.alpha

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
  SHA256:
3
- metadata.gz: d2850609edb1247c2c15d2b1b72b3d6f0c288201d1fb47ecc738d1c1987eeb48
4
- data.tar.gz: d0910dc9c2ad1f9a0788eb0daa0d83efffeb5a17471516702583590bc3003efc
3
+ metadata.gz: d61fbe056f88ae749567bcdd927e09a4c9d6b14cd42813495a49423e161f4bc7
4
+ data.tar.gz: 9c51b4f56fe3e4c7db3a4aecef92b1b96cd3b50d4537bee5c468839e3cfd746b
5
5
  SHA512:
6
- metadata.gz: 0ff117b80d6c392b5235fc5758251221411749832c262c2dbf62e41940962bf326de09026fff3719daf15d779692b7b3b57df6425d0db090d18b6f00eace5108
7
- data.tar.gz: f70010fc6fb6079569caf9c0c2a5f8f2ed952430e8d675bf48896a50ed68f5108d3b51810b3529962fc122a6d1bd9ac5a9a759ab99c94311eed5b7fdccab25cf
6
+ metadata.gz: 64cc246904617a66ba882fa6010cdb5a772a179191b53fbecf596628dd4e73e1e461f56b5f102df4c141837dd06c5b348567ac887c7bc7110b5b5fc4d29e3190
7
+ data.tar.gz: db3509825cbaea3ada1012d8e7c2fd5aea5efc612e8a2ab284a86a32ab9a38a0606b3ab8c6d219afe76cc3020830508d99eed3d8fab9886fc09d4174f92edf77
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  *.gem
3
3
  /tmp
4
4
  /coverage
5
+ /pkg
6
+ Gemfile.lock
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.0
1
+ 2.6.5
data/.travis.yml CHANGED
@@ -7,7 +7,7 @@ rvm:
7
7
  - 2.3.8
8
8
  - 2.4.5
9
9
  - 2.5.3
10
- - 2.6.0
10
+ - 2.6.5
11
11
  cache: bundler
12
12
  before_script:
13
13
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # 3.1.0-alpha (December 24th, 2019)
2
+
3
+ Additions/Changes:
4
+
5
+ * Added `Template#generate` option `bom` which will include the UTF-8 byte order mark.
6
+ * Ensured `Template#parse` ignores UTF-8 byte order marks, if one is present.
7
+
8
+ Internal:
9
+
10
+ * Cleaned up release process (added Rake)
11
+ * Removed internal attribute value resolution and replaced with [Objectable](https://github.com/bluemarblepayroll/objectable/tree/master/lib/objectable)
12
+ * Updated development dependencies
13
+
1
14
  # 3.0.1 (March 14th, 2019)
2
15
 
3
16
  * Add support for the following column syntax: ```column 'ID #', :id```, ```column = { 'ID #' => :id }```. If the second argument is not a hash, it will be converted to: ```{ property: value }```
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at oss@bluemarblepayroll.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/README.md CHANGED
@@ -68,7 +68,7 @@ Then we can explicitly map those as:
68
68
 
69
69
  ````ruby
70
70
  columns = {
71
- 'ID #' => :id },
71
+ 'ID #' => :id,
72
72
  'First Name' => :name,
73
73
  'Date of Birth' => :dob,
74
74
  'Phone #' => :phone
@@ -327,7 +327,7 @@ objects = Bumblebee::Template.new do |t|
327
327
  end.parse(data)
328
328
  ````
329
329
 
330
- ##### Subclassing ::Bumblebee::Template
330
+ ##### Subclassing Bumblebee::Template
331
331
 
332
332
  Another option is to subclass Template and declare your columns at the class-level:
333
333
 
@@ -380,6 +380,17 @@ end
380
380
 
381
381
  When executed to generate a CSV, the columns would be (in order): ```ID #, First Name, Middle Name, Last Name.```
382
382
 
383
+ ## Encoding Support
384
+
385
+ This library, currently, only supports UTF-8. You can choose to force the inclusion the UTF-8 [byte order mark](https://en.wikipedia.org/wiki/Byte_order_mark), for example:
386
+
387
+ ```ruby
388
+ csv = Bumblebee::Template.new(columns: columns).generate(objects, bom: true)
389
+ # csv will now start with "\xEF\xBB\xBF"
390
+ ```
391
+
392
+ UTF-8 byte order marks will also be ignored while parsing.
393
+
383
394
  ## Contributing
384
395
 
385
396
  ### Development Environment Configuration
@@ -419,14 +430,15 @@ Note: ensure you have proper authorization before trying to publish new versions
419
430
  After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
420
431
 
421
432
  1. Merge Pull Request into master
422
- 2. Update ```lib/bumblebee/version.rb``` using [semantic versioning](https://semver.org/)
423
- 3. Install dependencies: ```bundle```
424
- 4. Update ```CHANGELOG.md``` with release notes
433
+ 2. Update `lib/bumblebee/version.rb` using [semantic versioning](https://semver.org/)
434
+ 3. Install dependencies: `bundle`
435
+ 4. Update `CHANGELOG.md` with release notes
425
436
  5. Commit & push master to remote and ensure CI builds master successfully
426
- 6. Build the project locally: `gem build bumblebee`
427
- 7. Publish package to RubyGems: `gem push bumblebee-X.gem` where X is the version to push
428
- 8. Tag master with new version: `git tag <version>`
429
- 9. Push tags remotely: `git push origin --tags`
437
+ 6. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
438
+
439
+ ## Code of Conduct
440
+
441
+ Everyone interacting in this codebase, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/bluemarblepayroll/bumblebee/blob/master/CODE_OF_CONDUCT.md).
430
442
 
431
443
  ## License
432
444
 
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require 'bundler/gem_tasks'
11
+ require 'rspec/core/rake_task'
12
+ require 'rubocop/rake_task'
13
+
14
+ RSpec::Core::RakeTask.new(:spec)
15
+ RuboCop::RakeTask.new
16
+
17
+ task default: %i[rubocop spec]
data/bumblebee.gemspec CHANGED
@@ -23,11 +23,13 @@ Gem::Specification.new do |s|
23
23
  s.required_ruby_version = '>= 2.3.8'
24
24
 
25
25
  s.add_dependency('acts_as_hashable', '~>1.0')
26
+ s.add_dependency('objectable', '~>1.0')
26
27
 
27
28
  s.add_development_dependency('guard-rspec', '~>4.7')
28
- s.add_development_dependency('pry')
29
- s.add_development_dependency('rspec', '~> 3.8')
30
- s.add_development_dependency('rubocop', '~>0.63.1')
31
- s.add_development_dependency('simplecov', '~>0.16.1')
32
- s.add_development_dependency('simplecov-console', '~>0.4.2')
29
+ s.add_development_dependency('pry', '~>0')
30
+ s.add_development_dependency('rake', '~> 13')
31
+ s.add_development_dependency('rspec')
32
+ s.add_development_dependency('rubocop', '~>0.76.0')
33
+ s.add_development_dependency('simplecov', '~>0.17.0')
34
+ s.add_development_dependency('simplecov-console', '~>0.5.0')
33
35
  end
data/lib/bumblebee.rb CHANGED
@@ -7,4 +7,23 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require_relative 'bumblebee/bumblebee'
10
+ require 'bigdecimal'
11
+ require 'csv'
12
+ require 'date'
13
+ require 'forwardable'
14
+ require 'objectable'
15
+ require 'set'
16
+
17
+ # Monkey-patching core libaries
18
+ require_relative 'bumblebee/core_ext/hash'
19
+ Hash.include Bumblebee::CoreExt::Hash
20
+
21
+ # Load library
22
+ require_relative 'bumblebee/mutator'
23
+ require_relative 'bumblebee/null_converter'
24
+ require_relative 'bumblebee/converter'
25
+ require_relative 'bumblebee/simple_converter'
26
+ require_relative 'bumblebee/column'
27
+ require_relative 'bumblebee/column_set'
28
+ require_relative 'bumblebee/column_dsl'
29
+ require_relative 'bumblebee/template'
@@ -29,40 +29,34 @@ module Bumblebee
29
29
  @header = header.to_s
30
30
  @property = property || @header
31
31
  @through = Array(through)
32
- @to_csv = ::Bumblebee::Mutator.new(to_csv)
33
- @to_object = ::Bumblebee::Mutator.new(to_object)
32
+ @to_csv = Mutator.new(to_csv)
33
+ @to_object = Mutator.new(to_object)
34
+ @resolver = Objectable.resolver
34
35
 
35
36
  freeze
36
37
  end
37
38
 
38
39
  # Extract from object and set on hash
39
40
  def csv_set(data_object, hash)
40
- value = extract(traverse(data_object), property)
41
+ value = resolver.get(data_object, full_property)
41
42
 
42
43
  to_csv.set(hash, header, value)
43
44
  end
44
45
 
45
46
  def object_set(csv_object, hash)
46
- pointer = build(hash)
47
- value = csv_object[header]
47
+ value = csv_object[header]
48
48
 
49
- to_object.set(pointer, property, value)
49
+ to_object.set(hash, full_property, value)
50
50
 
51
51
  hash
52
52
  end
53
53
 
54
54
  private
55
55
 
56
- def traverse(object)
57
- ::Bumblebee::ObjectInterface.traverse(object, through)
58
- end
59
-
60
- def extract(object, key)
61
- ::Bumblebee::ObjectInterface.get(object, key)
62
- end
56
+ attr_reader :resolver
63
57
 
64
- def build(object)
65
- ::Bumblebee::ObjectInterface.build(object, through)
58
+ def full_property
59
+ through + [property]
66
60
  end
67
61
  end
68
62
  end
@@ -15,7 +15,7 @@ module Bumblebee
15
15
  def_delegators :column_set, :columns
16
16
 
17
17
  def column_set
18
- @column_set ||= ::Bumblebee::ColumnSet.new
18
+ @column_set ||= ColumnSet.new
19
19
  end
20
20
 
21
21
  def column(header, opts = {})
@@ -26,8 +26,8 @@ module Bumblebee
26
26
 
27
27
  def all_column_sets
28
28
  # the reverse preserves the order of inheritance to go from parent -> child
29
- ancestors.reverse_each.with_object(::Bumblebee::ColumnSet.new) do |ancestor, set|
30
- ancestor < ::Bumblebee::Template ? set.add(ancestor.columns) : set
29
+ ancestors.reverse_each.with_object(ColumnSet.new) do |ancestor, set|
30
+ ancestor < Template ? set.add(ancestor.columns) : set
31
31
  end
32
32
  end
33
33
 
@@ -15,7 +15,7 @@ module Bumblebee
15
15
  extend Forwardable
16
16
 
17
17
  FACTORY_ADD_METHODS = [
18
- [::Bumblebee::Column, :assign],
18
+ [Column, :assign],
19
19
  [Hash, :add_header_column_hash]
20
20
  ].freeze
21
21
 
@@ -32,7 +32,7 @@ module Bumblebee
32
32
  end
33
33
 
34
34
  def column(header, opts = {})
35
- column = ::Bumblebee::Column.new(header, normalize_opts(opts))
35
+ column = Column.new(header, normalize_opts(opts))
36
36
 
37
37
  column_hash[column.header] = column
38
38
 
@@ -57,7 +57,7 @@ module Bumblebee
57
57
 
58
58
  def add_header_column_hash(hash)
59
59
  hash.each_pair do |header, opts|
60
- column = ::Bumblebee::Column.new(header, normalize_opts(opts))
60
+ column = Column.new(header, normalize_opts(opts))
61
61
 
62
62
  assign(column)
63
63
  end
@@ -53,6 +53,8 @@ module Bumblebee
53
53
  @object_class = Hash
54
54
  end
55
55
 
56
+ @resolver = Objectable.resolver
57
+
56
58
  freeze
57
59
  end
58
60
 
@@ -62,6 +64,8 @@ module Bumblebee
62
64
 
63
65
  private
64
66
 
67
+ attr_reader :resolver
68
+
65
69
  def make_type(val)
66
70
  Types.const_get(val.to_s.upcase.to_sym)
67
71
  end
@@ -91,7 +95,7 @@ module Bumblebee
91
95
  end
92
96
 
93
97
  def make_converter(arg = nil)
94
- arg ? self.class.new(arg) : ::Bumblebee::NullConverter.new
98
+ arg ? self.class.new(arg) : NullConverter.new
95
99
  end
96
100
  end
97
101
  end
@@ -14,20 +14,21 @@ module Bumblebee
14
14
  module Types
15
15
  IGNORE = :ignore
16
16
  end
17
- include ::Bumblebee::Mutator::Types
17
+ include Mutator::Types
18
18
 
19
19
  attr_reader :converter, :type
20
20
 
21
21
  def initialize(arg)
22
+ @type = nil
23
+ @resolver = Objectable.resolver
24
+
22
25
  if arg.nil?
23
- @type = nil
24
- @converter = ::Bumblebee::NullConverter.new
26
+ @converter = NullConverter.new
25
27
  elsif mutator?(arg)
26
- @type = ::Bumblebee::Mutator::Types.const_get(arg.to_s.upcase.to_sym)
27
- @converter = ::Bumblebee::NullConverter.new
28
+ @type = Mutator::Types.const_get(arg.to_s.upcase.to_sym)
29
+ @converter = NullConverter.new
28
30
  else
29
- @type = nil
30
- @converter = ::Bumblebee::SimpleConverter.new(arg)
31
+ @converter = SimpleConverter.new(arg)
31
32
  end
32
33
 
33
34
  freeze
@@ -36,11 +37,13 @@ module Bumblebee
36
37
  def set(object, key, val)
37
38
  return object if ignore?
38
39
 
39
- ::Bumblebee::ObjectInterface.set(object, key, converter.convert(val))
40
+ resolver.set(object, key, converter.convert(val))
40
41
  end
41
42
 
42
43
  private
43
44
 
45
+ attr_reader :resolver
46
+
44
47
  def ignore?
45
48
  type == IGNORE
46
49
  end
@@ -48,7 +51,7 @@ module Bumblebee
48
51
  def mutator?(arg)
49
52
  return false unless arg.is_a?(String) || arg.is_a?(Symbol)
50
53
 
51
- ::Bumblebee::Mutator::Types.constants.include?(arg.to_s.upcase.to_sym)
54
+ Types.constants.include?(arg.to_s.upcase.to_sym)
52
55
  end
53
56
  end
54
57
  end
@@ -9,8 +9,8 @@
9
9
 
10
10
  module Bumblebee
11
11
  # Subclass of Converter that provides a simple implementation for each Type.
12
- class SimpleConverter < ::Bumblebee::Converter
13
- DEFAULT_DATE = '1900-01-01'
12
+ class SimpleConverter < Converter
13
+ DEFAULT_DATE = '1900-01-01'
14
14
  DEFAULT_BIG_DECIMAL = 0
15
15
 
16
16
  private
@@ -18,7 +18,7 @@ module Bumblebee
18
18
  def process_pluck_join(val)
19
19
  raise ArgumentError, 'sub_property is required for a pluck_join' unless sub_property
20
20
 
21
- Array(val).map { |h| per.convert(::Bumblebee::ObjectInterface.get(h, sub_property)) }
21
+ Array(val).map { |h| per.convert(resolver.get(h, sub_property)) }
22
22
  .join(separator)
23
23
  end
24
24
 
@@ -26,7 +26,7 @@ module Bumblebee
26
26
  raise ArgumentError, 'sub_property is required for a pluck_split' unless sub_property
27
27
 
28
28
  process_split(val).map do |v|
29
- object_class.new.tap { |h| ::Bumblebee::ObjectInterface.set(h, sub_property, v) }
29
+ object_class.new.tap { |h| resolver.set(h, sub_property, v) }
30
30
  end
31
31
  end
32
32
 
@@ -13,14 +13,14 @@ module Bumblebee
13
13
  # parse_csv: take in a string and return an array of hashes
14
14
  class Template
15
15
  extend Forwardable
16
- extend ::Bumblebee::ColumnDsl
16
+ extend ColumnDsl
17
17
 
18
18
  def_delegators :column_set, :headers, :columns
19
19
 
20
20
  attr_reader :object_class
21
21
 
22
22
  def initialize(columns: nil, object_class: Hash, &block)
23
- @column_set = ::Bumblebee::ColumnSet.new(self.class.all_columns)
23
+ @column_set = ColumnSet.new(self.class.all_columns)
24
24
  @object_class = object_class
25
25
 
26
26
  column_set.add(columns)
@@ -40,12 +40,19 @@ module Bumblebee
40
40
  self
41
41
  end
42
42
 
43
- def generate(objects, options = {})
44
- objects = objects.is_a?(Hash) ? [objects] : Array(objects)
43
+ BOM = :bom
44
+ UTF8_BOM = "\xEF\xBB\xBF"
45
+
46
+ CUSTOM_OPTIONS = [
47
+ BOM
48
+ ].to_set.freeze
45
49
 
46
- write_options = options.merge(headers: headers, write_headers: true)
50
+ def generate(objects, options = {})
51
+ objects = array(objects)
52
+ options = parse_options(options)
53
+ prefix = options.bom ? UTF8_BOM : ''
47
54
 
48
- CSV.generate(write_options) do |csv|
55
+ prefix + CSV.generate(options.ruby_csv_options) do |csv|
49
56
  objects.each do |object|
50
57
  csv << columns.each_with_object({}) do |column, hash|
51
58
  column.csv_set(object, hash)
@@ -55,7 +62,9 @@ module Bumblebee
55
62
  end
56
63
 
57
64
  def parse(string, options = {})
58
- csv = CSV.new(string, options.merge(headers: true))
65
+ string_without_bom = string.sub(UTF8_BOM, '')
66
+
67
+ csv = CSV.new(string_without_bom, options.merge(headers: true))
59
68
 
60
69
  csv.to_a.map do |row|
61
70
  # Build up a hash using the column one at a time
@@ -67,6 +76,24 @@ module Bumblebee
67
76
 
68
77
  private
69
78
 
79
+ Options = Struct.new(:ruby_csv_options, :bom)
80
+
81
+ private_constant :Options
82
+
70
83
  attr_reader :column_set
84
+
85
+ def array(objects)
86
+ objects.is_a?(Hash) ? [objects] : Array(objects)
87
+ end
88
+
89
+ def parse_options(options)
90
+ options = (options || {}).symbolize_keys
91
+ bom = options[BOM] || false
92
+
93
+ ruby_csv_options = options.merge(headers: headers, write_headers: true)
94
+ .reject { |k| CUSTOM_OPTIONS.include?(k) }
95
+
96
+ Options.new(ruby_csv_options, bom)
97
+ end
71
98
  end
72
99
  end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Bumblebee
11
- VERSION = '3.0.1'
11
+ VERSION = '3.1.0-alpha'
12
12
  end
@@ -10,11 +10,11 @@
10
10
  require 'spec_helper'
11
11
  require './spec/examples/converter_test_case'
12
12
 
13
- describe ::Bumblebee::SimpleConverter do
13
+ describe Bumblebee::SimpleConverter do
14
14
  describe '#convert' do
15
15
  ConverterTestCase.all.each do |test_case|
16
16
  it "should convert: #{test_case.arg}" do
17
- converter = ::Bumblebee::SimpleConverter.new(test_case.arg)
17
+ converter = Bumblebee::SimpleConverter.new(test_case.arg)
18
18
 
19
19
  test_case.convert_cases.each do |convert_case|
20
20
  input = convert_case.first
@@ -11,7 +11,7 @@ require 'spec_helper'
11
11
  require 'examples/person_template'
12
12
  require 'examples/simple_object'
13
13
 
14
- describe ::Bumblebee::Template do
14
+ describe Bumblebee::Template do
15
15
  describe 'array/string-based columns and symbol based object keys' do
16
16
  let(:data_objects) { yaml_fixture('simple', 'data.yml').map(&:symbolize_keys) }
17
17
 
@@ -19,7 +19,7 @@ describe ::Bumblebee::Template do
19
19
 
20
20
  let(:columns) { yaml_fixture('simple', 'columns.yml') }
21
21
 
22
- subject { ::Bumblebee::Template.new(columns: columns) }
22
+ subject { Bumblebee::Template.new(columns: columns) }
23
23
 
24
24
  specify '#generate_csv properly builds a CSV-formatted string' do
25
25
  actual = subject.generate(data_objects)
@@ -45,7 +45,7 @@ describe ::Bumblebee::Template do
45
45
 
46
46
  let(:columns) { yaml_fixture('simple', 'columns.yml') }
47
47
 
48
- subject { ::Bumblebee::Template.new(columns: columns, object_class: OpenStruct) }
48
+ subject { Bumblebee::Template.new(columns: columns, object_class: OpenStruct) }
49
49
 
50
50
  specify '#generate_csv properly builds a CSV-formatted string' do
51
51
  actual = subject.generate(data_objects)
@@ -69,7 +69,7 @@ describe ::Bumblebee::Template do
69
69
 
70
70
  let(:columns) { yaml_fixture('simple', 'columns.yml') }
71
71
 
72
- subject { ::Bumblebee::Template.new(columns: columns, object_class: SimpleObject) }
72
+ subject { Bumblebee::Template.new(columns: columns, object_class: SimpleObject) }
73
73
 
74
74
  specify '#generate_csv properly builds a CSV-formatted string' do
75
75
  actual = subject.generate(data_objects)
@@ -91,7 +91,7 @@ describe ::Bumblebee::Template do
91
91
 
92
92
  let(:columns) { yaml_fixture('registrations', 'columns.yml') }
93
93
 
94
- subject { ::Bumblebee::Template.new(columns: columns) }
94
+ subject { Bumblebee::Template.new(columns: columns) }
95
95
 
96
96
  specify '#generate_csv properly builds a CSV-formatted string' do
97
97
  actual = subject.generate(data_objects)
@@ -114,7 +114,7 @@ describe ::Bumblebee::Template do
114
114
  let(:columns) { yaml_fixture('registrations', 'columns.yml') }
115
115
 
116
116
  subject do
117
- ::Bumblebee::Template.new do |t|
117
+ Bumblebee::Template.new do |t|
118
118
  columns.each do |header, opts|
119
119
  t.column(header, opts)
120
120
  end
@@ -140,7 +140,7 @@ describe ::Bumblebee::Template do
140
140
  let(:csv_file) { fixture('registrations', 'data.csv') }
141
141
 
142
142
  subject do
143
- ::Bumblebee::Template.new do
143
+ Bumblebee::Template.new do
144
144
  columns = yaml_fixture('registrations', 'columns.yml')
145
145
  columns.each do |header, opts|
146
146
  column(header, opts)
@@ -184,4 +184,30 @@ describe ::Bumblebee::Template do
184
184
  expect(actual).to eq(data_objects)
185
185
  end
186
186
  end
187
+
188
+ describe 'UTF-8 Byte Order Mark (BOM) support' do
189
+ let(:data_objects) { yaml_fixture('simple', 'data.yml').map(&:symbolize_keys) }
190
+
191
+ let(:csv_file) { fixture('simple', 'data.csv') }
192
+
193
+ let(:columns) { yaml_fixture('simple', 'columns.yml') }
194
+
195
+ subject { Bumblebee::Template.new(columns: columns) }
196
+
197
+ specify '#generate_csv includes BOM' do
198
+ actual = subject.generate(data_objects, bom: true)
199
+
200
+ expect(actual).to start_with("\xEF\xBB\xBF")
201
+ end
202
+
203
+ specify '#parse excludes BOM' do
204
+ utf8_string_with_bom = "\xEF\xBB\xBF#{csv_file}"
205
+
206
+ expect(utf8_string_with_bom.encoding).to eq(Encoding::UTF_8)
207
+
208
+ actual = subject.parse(utf8_string_with_bom).map(&:symbolize_keys)
209
+
210
+ expect(actual).to eq(data_objects)
211
+ end
212
+ end
187
213
  end
@@ -7,7 +7,7 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- class PersonTemplate < ::Bumblebee::Template
10
+ class PersonTemplate < Bumblebee::Template
11
11
  column 'ID #', property: 'id',
12
12
  to_object: :integer
13
13
 
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,7 @@
10
10
  require 'stringio'
11
11
  require 'pry'
12
12
  require 'ostruct'
13
+ require 'yaml'
13
14
 
14
15
  require 'simplecov'
15
16
  require 'simplecov-console'
@@ -44,7 +45,7 @@ end
44
45
 
45
46
  def manually_convert_csv_object(csv_object, columns)
46
47
  csv_object.map do |header, value|
47
- column = ::Bumblebee::Column.new(header, columns[header].symbolize_keys)
48
+ column = Bumblebee::Column.new(header, columns[header].symbolize_keys)
48
49
 
49
50
  converted_value =
50
51
  if column.extractor.expect_array?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bumblebee
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-14 00:00:00.000000000 Z
11
+ date: 2019-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: objectable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: guard-rspec
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -42,72 +56,86 @@ dependencies:
42
56
  name: pry
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - ">="
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ">="
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: rspec
70
+ name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '3.8'
75
+ version: '13'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '3.8'
82
+ version: '13'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rubocop
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: 0.63.1
103
+ version: 0.76.0
76
104
  type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
- version: 0.63.1
110
+ version: 0.76.0
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: simplecov
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
- version: 0.16.1
117
+ version: 0.17.0
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
- version: 0.16.1
124
+ version: 0.17.0
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: simplecov-console
99
127
  requirement: !ruby/object:Gem::Requirement
100
128
  requirements:
101
129
  - - "~>"
102
130
  - !ruby/object:Gem::Version
103
- version: 0.4.2
131
+ version: 0.5.0
104
132
  type: :development
105
133
  prerelease: false
106
134
  version_requirements: !ruby/object:Gem::Requirement
107
135
  requirements:
108
136
  - - "~>"
109
137
  - !ruby/object:Gem::Version
110
- version: 0.4.2
138
+ version: 0.5.0
111
139
  description: |2
112
140
  Higher level languages, such as Ruby, make interacting with CSVs trivial.
113
141
  Even so, this library provides a very simple object/csv mapper that allows you to fully interact with CSVs in a declarative way.
@@ -124,15 +152,15 @@ files:
124
152
  - ".ruby-version"
125
153
  - ".travis.yml"
126
154
  - CHANGELOG.md
155
+ - CODE_OF_CONDUCT.md
127
156
  - Gemfile
128
- - Gemfile.lock
129
157
  - Guardfile
130
158
  - LICENSE
131
159
  - README.md
160
+ - Rakefile
132
161
  - bin/console
133
162
  - bumblebee.gemspec
134
163
  - lib/bumblebee.rb
135
- - lib/bumblebee/bumblebee.rb
136
164
  - lib/bumblebee/column.rb
137
165
  - lib/bumblebee/column_dsl.rb
138
166
  - lib/bumblebee/column_set.rb
@@ -140,7 +168,6 @@ files:
140
168
  - lib/bumblebee/core_ext/hash.rb
141
169
  - lib/bumblebee/mutator.rb
142
170
  - lib/bumblebee/null_converter.rb
143
- - lib/bumblebee/object_interface.rb
144
171
  - lib/bumblebee/simple_converter.rb
145
172
  - lib/bumblebee/template.rb
146
173
  - lib/bumblebee/version.rb
@@ -173,11 +200,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
173
200
  version: 2.3.8
174
201
  required_rubygems_version: !ruby/object:Gem::Requirement
175
202
  requirements:
176
- - - ">="
203
+ - - ">"
177
204
  - !ruby/object:Gem::Version
178
- version: '0'
205
+ version: 1.3.1
179
206
  requirements: []
180
- rubygems_version: 3.0.1
207
+ rubygems_version: 3.0.3
181
208
  signing_key:
182
209
  specification_version: 4
183
210
  summary: Object/CSV Mapper
data/Gemfile.lock DELETED
@@ -1,105 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- bumblebee (3.0.1)
5
- acts_as_hashable (~> 1.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- acts_as_hashable (1.0.5)
11
- ansi (1.5.0)
12
- ast (2.4.0)
13
- coderay (1.1.2)
14
- diff-lcs (1.3)
15
- docile (1.3.1)
16
- ffi (1.9.25)
17
- formatador (0.2.5)
18
- guard (2.15.0)
19
- formatador (>= 0.2.4)
20
- listen (>= 2.7, < 4.0)
21
- lumberjack (>= 1.0.12, < 2.0)
22
- nenv (~> 0.1)
23
- notiffany (~> 0.0)
24
- pry (>= 0.9.12)
25
- shellany (~> 0.0)
26
- thor (>= 0.18.1)
27
- guard-compat (1.2.1)
28
- guard-rspec (4.7.3)
29
- guard (~> 2.1)
30
- guard-compat (~> 1.1)
31
- rspec (>= 2.99.0, < 4.0)
32
- hirb (0.7.3)
33
- jaro_winkler (1.5.2)
34
- json (2.1.0)
35
- listen (3.1.5)
36
- rb-fsevent (~> 0.9, >= 0.9.4)
37
- rb-inotify (~> 0.9, >= 0.9.7)
38
- ruby_dep (~> 1.2)
39
- lumberjack (1.0.13)
40
- method_source (0.9.2)
41
- nenv (0.3.0)
42
- notiffany (0.1.1)
43
- nenv (~> 0.1)
44
- shellany (~> 0.0)
45
- parallel (1.13.0)
46
- parser (2.6.0.0)
47
- ast (~> 2.4.0)
48
- powerpack (0.1.2)
49
- pry (0.12.2)
50
- coderay (~> 1.1.0)
51
- method_source (~> 0.9.0)
52
- rainbow (3.0.0)
53
- rb-fsevent (0.10.3)
54
- rb-inotify (0.9.10)
55
- ffi (>= 0.5.0, < 2)
56
- rspec (3.8.0)
57
- rspec-core (~> 3.8.0)
58
- rspec-expectations (~> 3.8.0)
59
- rspec-mocks (~> 3.8.0)
60
- rspec-core (3.8.0)
61
- rspec-support (~> 3.8.0)
62
- rspec-expectations (3.8.2)
63
- diff-lcs (>= 1.2.0, < 2.0)
64
- rspec-support (~> 3.8.0)
65
- rspec-mocks (3.8.0)
66
- diff-lcs (>= 1.2.0, < 2.0)
67
- rspec-support (~> 3.8.0)
68
- rspec-support (3.8.0)
69
- rubocop (0.63.1)
70
- jaro_winkler (~> 1.5.1)
71
- parallel (~> 1.10)
72
- parser (>= 2.5, != 2.5.1.1)
73
- powerpack (~> 0.1)
74
- rainbow (>= 2.2.2, < 4.0)
75
- ruby-progressbar (~> 1.7)
76
- unicode-display_width (~> 1.4.0)
77
- ruby-progressbar (1.10.0)
78
- ruby_dep (1.5.0)
79
- shellany (0.0.1)
80
- simplecov (0.16.1)
81
- docile (~> 1.1)
82
- json (>= 1.8, < 3)
83
- simplecov-html (~> 0.10.0)
84
- simplecov-console (0.4.2)
85
- ansi
86
- hirb
87
- simplecov
88
- simplecov-html (0.10.2)
89
- thor (0.20.3)
90
- unicode-display_width (1.4.1)
91
-
92
- PLATFORMS
93
- ruby
94
-
95
- DEPENDENCIES
96
- bumblebee!
97
- guard-rspec (~> 4.7)
98
- pry
99
- rspec (~> 3.8)
100
- rubocop (~> 0.63.1)
101
- simplecov (~> 0.16.1)
102
- simplecov-console (~> 0.4.2)
103
-
104
- BUNDLED WITH
105
- 1.17.3
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright (c) 2018-present, Blue Marble Payroll, LLC
5
- #
6
- # This source code is licensed under the MIT license found in the
7
- # LICENSE file in the root directory of this source tree.
8
- #
9
-
10
- require 'bigdecimal'
11
- require 'csv'
12
- require 'date'
13
- require 'forwardable'
14
-
15
- # Monkey-patching core libaries
16
- require_relative 'core_ext/hash'
17
- Hash.include ::Bumblebee::CoreExt::Hash
18
-
19
- # Load library
20
- require_relative 'object_interface'
21
- require_relative 'mutator'
22
- require_relative 'null_converter'
23
- require_relative 'converter'
24
- require_relative 'simple_converter'
25
- require_relative 'column'
26
- require_relative 'column_set'
27
- require_relative 'column_dsl'
28
- require_relative 'template'
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright (c) 2018-present, Blue Marble Payroll, LLC
5
- #
6
- # This source code is licensed under the MIT license found in the
7
- # LICENSE file in the root directory of this source tree.
8
- #
9
-
10
- module Bumblebee
11
- # Provides methods for interacting with custom objects.
12
- class ObjectInterface
13
- class << self
14
- def traverse(object, through)
15
- pointer = object
16
-
17
- through.each do |t|
18
- next unless pointer
19
-
20
- pointer = get(pointer, t)
21
- end
22
-
23
- pointer
24
- end
25
-
26
- def build(object, through)
27
- pointer = object
28
-
29
- through.each do |t|
30
- pointer = get(pointer, t) || get(set(pointer, t, pointer.class.new), t)
31
- end
32
-
33
- pointer
34
- end
35
-
36
- def set(object, key, val)
37
- object.tap do |o|
38
- setter_method = "#{key}="
39
- if o.respond_to?(setter_method)
40
- o.send(setter_method, val)
41
- elsif o.respond_to?(:[])
42
- o[key] = val
43
- end
44
- end
45
- end
46
-
47
- def get(object, key)
48
- if object.is_a?(Hash)
49
- indifferent_hash_get(object, key)
50
- elsif object.respond_to?(key)
51
- object.send(key)
52
- end
53
- end
54
-
55
- private
56
-
57
- def indifferent_hash_get(hash, key)
58
- if hash.key?(key.to_s)
59
- hash[key.to_s]
60
- elsif hash.key?(key.to_s.to_sym)
61
- hash[key.to_s.to_sym]
62
- end
63
- end
64
- end
65
- end
66
- end