From e69818dd011f2d18dc21968b33093ee52f2bf333 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Thu, 2 Feb 2017 21:48:17 +0100 Subject: [PATCH] Add Tags field class to hold tags on a Buffer --- lib/rackstash/fields.rb | 1 + lib/rackstash/fields/abstract_collection.rb | 2 +- lib/rackstash/fields/tags.rb | 69 ++++++++++++ spec/rackstash/fields/tags_spec.rb | 118 ++++++++++++++++++++ 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 lib/rackstash/fields/tags.rb create mode 100644 spec/rackstash/fields/tags_spec.rb diff --git a/lib/rackstash/fields.rb b/lib/rackstash/fields.rb index 1252d8f..f408fe4 100644 --- a/lib/rackstash/fields.rb +++ b/lib/rackstash/fields.rb @@ -6,3 +6,4 @@ require 'rackstash/fields/abstract_collection' require 'rackstash/fields/hash' require 'rackstash/fields/array' +require 'rackstash/fields/tags' diff --git a/lib/rackstash/fields/abstract_collection.rb b/lib/rackstash/fields/abstract_collection.rb index 040169c..fbb4bec 100644 --- a/lib/rackstash/fields/abstract_collection.rb +++ b/lib/rackstash/fields/abstract_collection.rb @@ -89,7 +89,7 @@ module Rackstash hash_field.raw = hash end if wrap return hash - when ::Array, ::Enumerator + when ::Array, ::Set, ::Enumerator array = value.map { |e| normalize(e, scope: scope, resolve: resolve) } array = Rackstash::Fields::Array.new.tap do |array_field| array_field.raw = array diff --git a/lib/rackstash/fields/tags.rb b/lib/rackstash/fields/tags.rb new file mode 100644 index 0000000..d5edbb5 --- /dev/null +++ b/lib/rackstash/fields/tags.rb @@ -0,0 +1,69 @@ +# Copyright 2017 Holger Just +# +# This software may be modified and distributed under the terms +# of the MIT license. See the LICENSE.txt file for details. + +require 'set' + +require 'rackstash/fields/abstract_collection' + +module Rackstash + module Fields + class Tags < AbstractCollection + def initialize + @raw = Set.new + end + + def <<(tag) + merge!(tag) + end + + def as_json(*) + @raw.to_a + end + alias :to_ary :as_json + alias :to_a :as_json + + def clear + @raw.clear + self + end + + def empty? + @raw.empty? + end + + def merge(*tags, scope: nil) + dup.merge!(*tags, scope: scope) + end + + def merge!(*tags, scope: nil) + @raw.merge normalize_tags(tags.to_ary) + self + end + + def tagged?(tag) + @raw.include? utf8_encode(tag) + end + + def to_set + @raw.dup + end + + protected + + def normalize_tags(value, scope: nil) + value = resolve_value(value, scope: scope) + + if value.respond_to?(:to_ary) + value = value.to_ary.map { |tag| normalize_tags(tag) } + value.flatten! + value + else + utf8_encode(value).freeze + end + end + end + end +end + diff --git a/spec/rackstash/fields/tags_spec.rb b/spec/rackstash/fields/tags_spec.rb new file mode 100644 index 0000000..9e9c4bd --- /dev/null +++ b/spec/rackstash/fields/tags_spec.rb @@ -0,0 +1,118 @@ +# Copyright 2017 Holger Just +# +# This software may be modified and distributed under the terms +# of the MIT license. See the LICENSE.txt file for details. + +require 'spec_helper' + +require 'rackstash/fields/tags' + +describe Rackstash::Fields::Tags do + let(:tags) { Rackstash::Fields::Tags.new } + + describe '#<<' do + it 'calls merge!' do + expect(tags).to receive(:merge!).with('tag').and_call_original + tags << 'tag' + expect(tags.tagged?('tag')).to be true + end + end + + describe '#as_json' do + before do + tags.merge!(123, 'tag', true) + end + + it 'returns a simple array' do + expect(tags.as_json).to be_a ::Array + expect(tags.as_json).to eql ['123', 'tag', 'true'] + end + + it 'returns a new copy each time' do + expect(tags.as_json).to eql tags.as_json + expect(tags.as_json).not_to equal tags.as_json + end + + it 'can use to_ary as an alias' do + expect(tags.to_ary).to eql tags.as_json + end + + it 'can use to_a as an alias' do + expect(tags.to_a).to eql tags.as_json + end + end + + describe '#clear' do + it 'clears all tags' do + tags << 'beep' + tags.clear + expect(tags.to_a).to be_empty + end + + it 'returns the tags' do + tags << 'beep' + expect(tags.clear).to equal tags + end + end + + describe '#empty?' do + it 'returns true of there are any tags' do + expect(tags.empty?).to be true + tags << 'foo' + expect(tags.empty?).to be false + tags.clear + expect(tags.empty?).to be true + end + end + + describe '#merge' do + it 'returns a new object' do + new_tags = tags.merge('hello') + + expect(new_tags).to be_a Rackstash::Fields::Tags + expect(new_tags.tagged?('hello')).to be true + expect(new_tags).not_to equal tags + + # The original hash is not changed + expect(tags.tagged?('hello')).to be false + end + end + + describe '#merge!' do + it 'merges multiple tags as strings' do + tags.merge! 'foo', 'bar' + expect(tags.to_a).to eql ['foo', 'bar'] + + tags.merge! 123, 'foo', nil + expect(tags.to_a).to eql ['foo', 'bar', '123', ''] + + expect(tags.to_a).to all be_frozen + end + end + + describe '#tagged?' do + it 'checks is the argument is tagged' do + tags.merge! 'foo', '123' + + expect(tags.tagged?('foo')).to be true + expect(tags.tagged?(:foo)).to be true + expect(tags.tagged?(123)).to be true + expect(tags.tagged?('123')).to be true + + expect(tags.tagged?(nil)).to be false + expect(tags.tagged?('bar')).to be false + end + end + + describe 'to_set' do + it 'returns a copy of the internal set' do + expect(tags.to_set).to be_a Set + + tags.merge! 'foo', nil + + expect(tags.to_set.include?('foo')).to be true + expect(tags.to_set.include?(nil)).to be false + expect(tags.to_set.include?('')).to be true + end + end +end