diff --git a/.rubocop.yml b/.rubocop.yml index 759498e..b5a58ca 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,6 +6,8 @@ Style/SymbolArray: EnforcedStyle: brackets Style/WordArray: EnforcedStyle: brackets +Style/OpenStructUse: + Enabled: false Metrics/BlockLength: Exclude: - 'spec/**/*_spec.rb' @@ -15,3 +17,5 @@ Layout/EndAlignment: EnforcedStyleAlignWith: variable Layout/FirstArrayElementIndentation: EnforcedStyle: consistent +Gemspec/DevelopmentDependencies: + Enabled: false diff --git a/lib/nazar.rb b/lib/nazar.rb index a4b01a2..5100f93 100644 --- a/lib/nazar.rb +++ b/lib/nazar.rb @@ -38,12 +38,12 @@ module Nazar # rubocop:disable Metrics/ModuleLength setting :enable_shorthand_method, default: true - class << self + class << self # rubocop:disable Metrics/ClassLength def formatters @formatters ||= Set.new end - def enable!(extensions: [:active_record, :csv]) + def enable!(extensions: [:active_record, :csv, :struct]) return if @enabled load_extensions!(extensions) @@ -67,6 +67,12 @@ def load_csv! register_formatter!('CSVTable', 'nazar/formatter/csv_table') end + def load_struct! + require 'ostruct' + + register_formatter!('Struct', 'nazar/formatter/struct') + end + def load_active_record! require 'active_record' @@ -113,6 +119,7 @@ def disable! def load_extensions!(extensions) load_active_record! if extensions.include?(:active_record) load_csv! if extensions.include?(:csv) + load_struct! if extensions.include?(:struct) load_sequel! if extensions.include?(:sequel) end diff --git a/lib/nazar/formatter/active_record_collection.rb b/lib/nazar/formatter/active_record_collection.rb index 74a541c..8d8a656 100644 --- a/lib/nazar/formatter/active_record_collection.rb +++ b/lib/nazar/formatter/active_record_collection.rb @@ -16,6 +16,8 @@ def initialize(collection) end def self.valid?(data) + return false if data.is_a?(Struct) || (defined?(OpenStruct) && data.is_a?(OpenStruct)) + data.is_a?(ActiveRecord::Associations::CollectionProxy) || data.is_a?(ActiveRecord::Relation) || (data.is_a?(Enumerable) && data.first.is_a?(ActiveRecord::Base)) diff --git a/lib/nazar/formatter/generic.rb b/lib/nazar/formatter/generic.rb index e908757..cbd3b91 100644 --- a/lib/nazar/formatter/generic.rb +++ b/lib/nazar/formatter/generic.rb @@ -27,10 +27,10 @@ def summary end def self.valid?(data) - item = data&.first - compatible = item.respond_to?(:keys) && item.respond_to?(:values) + return false unless data.is_a?(Enumerable) - data.is_a?(Enumerable) && (item.is_a?(Struct) || compatible) + item = data&.first + item.respond_to?(:keys) && item.respond_to?(:values) end def valid? diff --git a/lib/nazar/formatter/struct.rb b/lib/nazar/formatter/struct.rb new file mode 100644 index 0000000..5be1eb9 --- /dev/null +++ b/lib/nazar/formatter/struct.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Nazar + module Formatter + class Struct + def initialize(item) + @collection = Array(item) + @attributes = item.to_h.keys + @item = item + end + + def self.valid?(data) + data.is_a?(::Struct) || data.is_a?(::OpenStruct) + end + + def valid? + true + end + + def headers + HeadersFormatter.new(attributes).format + end + + def cells + @cells ||= @collection.map do |item| + item.each_pair do |_, value| + CellFormatter.new(value, type: nil).format + end + end + end + end + end +end diff --git a/lib/nazar/version.rb b/lib/nazar/version.rb index 623c65d..3b1c33a 100644 --- a/lib/nazar/version.rb +++ b/lib/nazar/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Nazar - VERSION = '1.2.0' + VERSION = '1.3.0' end diff --git a/spec/nazar/view_spec.rb b/spec/nazar/view_spec.rb index 77a5860..b563916 100644 --- a/spec/nazar/view_spec.rb +++ b/spec/nazar/view_spec.rb @@ -62,6 +62,30 @@ end end end + + context 'with Struct' do + let(:data) { Struct.new(:id, :name).new(1, 'foo') } + + context 'without loaded extension' do + it do + expect(subject).not_to be_supported_data + end + end + + context 'with loaded extension' do + before do + Nazar.load_struct! + end + + after do + unload_struct! + end + + it do + expect(subject).to be_supported_data + end + end + end end describe '#render' do diff --git a/spec/nazar_spec.rb b/spec/nazar_spec.rb index f55e8c9..f48cc71 100644 --- a/spec/nazar_spec.rb +++ b/spec/nazar_spec.rb @@ -15,7 +15,7 @@ context 'when Pry is defined' do it do - ::Pry = double + ::Pry = double # rubocop:disable Style/RedundantConstantBase expect(Nazar).to receive(:enable_for_pry!) expect(Nazar).not_to receive(:enable_for_irb!) @@ -26,7 +26,7 @@ context 'when IRB is defined' do it do - ::IRB = double + ::IRB = double # rubocop:disable Style/RedundantConstantBase expect(Nazar).not_to receive(:enable_for_pry!) expect(Nazar).to receive(:enable_for_irb!) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 800d36e..547c6a6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -24,6 +24,10 @@ def unload_sequel! Nazar.formatters.delete(Nazar::Formatter::SequelCollection) Nazar.formatters.delete(Nazar::Formatter::SequelItem) end + + def unload_struct! + Nazar.formatters.delete(Nazar::Formatter::Struct) + end end end