From 781f8ae13221660a83f885b2264952cd4fbc6889 Mon Sep 17 00:00:00 2001 From: Yen-Nan Lin Date: Mon, 31 Jul 2017 17:50:48 +0800 Subject: Support custom indent string --- lib/plist/generator.rb | 42 ++++++++++++++++++++++-------------------- test/test_generator.rb | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/lib/plist/generator.rb b/lib/plist/generator.rb index 21ef959..7a5b8d5 100644 --- a/lib/plist/generator.rb +++ b/lib/plist/generator.rb @@ -22,14 +22,16 @@ module Plist # # For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below. module Emit + DEFAULT_INDENT = "\t".freeze + # Helper method for injecting into classes. Calls Plist::Emit.dump with +self+. - def to_plist(envelope = true) - return Plist::Emit.dump(self, envelope) + def to_plist(envelope = true, indent: DEFAULT_INDENT) + return Plist::Emit.dump(self, envelope, indent: indent) end # Helper method for injecting into classes. Calls Plist::Emit.save_plist with +self+. - def save_plist(filename) - Plist::Emit.save_plist(self, filename) + def save_plist(filename, indent: DEFAULT_INDENT) + Plist::Emit.save_plist(self, filename, indent: indent) end # The following Ruby classes are converted into native plist types: @@ -40,8 +42,8 @@ module Plist # +IO+ and +StringIO+ objects are encoded and placed in elements; other objects are Marshal.dump'ed unless they implement +to_plist_node+. # # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment. - def self.dump(obj, envelope = true) - output = plist_node(obj) + def self.dump(obj, envelope = true, indent: DEFAULT_INDENT) + output = plist_node(obj, indent: indent) output = wrap(output) if envelope @@ -49,14 +51,14 @@ module Plist end # Writes the serialized object's plist to the specified filename. - def self.save_plist(obj, filename) + def self.save_plist(obj, filename, indent: DEFAULT_INDENT) File.open(filename, 'wb') do |f| - f.write(obj.to_plist) + f.write(obj.to_plist(indent: indent)) end end private - def self.plist_node(element) + def self.plist_node(element, indent: DEFAULT_INDENT) output = '' if element.respond_to? :to_plist_node @@ -67,7 +69,7 @@ module Plist if element.empty? output << "\n" else - output << tag('array') { + output << tag('array', indent: indent) { element.collect {|e| plist_node(e)} } end @@ -79,22 +81,22 @@ module Plist element.keys.sort_by{|k| k.to_s }.each do |k| v = element[k] - inner_tags << tag('key', CGI.escapeHTML(k.to_s)) - inner_tags << plist_node(v) + inner_tags << tag('key', CGI.escapeHTML(k.to_s), indent: indent) + inner_tags << plist_node(v, indent: indent) end - output << tag('dict') { + output << tag('dict', indent: indent) { inner_tags } end when true, false output << "<#{element}/>\n" when Time - output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ')) + output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), indent: indent) when Date # also catches DateTime - output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ')) + output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'), indent: indent) when String, Symbol, Integer, Float - output << tag(element_type(element), CGI.escapeHTML(element.to_s)) + output << tag(element_type(element), CGI.escapeHTML(element.to_s), indent: indent) when IO, StringIO element.rewind contents = element.read @@ -104,12 +106,12 @@ module Plist # because b64encode is b0rked and ignores the length arg. data = "\n" Base64.encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } - output << tag('data', data) + output << tag('data', data, indent: indent) else output << comment('The element below contains a Ruby object which has been serialized with Marshal.dump.') data = "\n" Base64.encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } - output << tag('data', data) + output << tag('data', data, indent: indent) end end @@ -120,11 +122,11 @@ module Plist return "\n" end - def self.tag(type, contents = '', &block) + def self.tag(type, contents = '', indent: DEFAULT_INDENT, &block) out = nil if block_given? - out = IndentedString.new + out = IndentedString.new(indent) out << "<#{type}>" out.raise_indent diff --git a/test/test_generator.rb b/test/test_generator.rb index e03c49d..71974dd 100644 --- a/test/test_generator.rb +++ b/test/test_generator.rb @@ -70,4 +70,41 @@ class TestGenerator < Test::Unit::TestCase assert_equal expected, output.gsub(/[\t]/, "\s\s") end + + def test_custom_indent + hsh = { key1: 1, 'key2' => 2 } + output_plist_node = Plist::Emit.plist_node(hsh, indent: nil) + output_plist_dump_with_envelope = Plist::Emit.dump(hsh, indent: nil) + output_plist_dump_no_envelope = Plist::Emit.dump(hsh, false, indent: nil) + + expected_with_envelope = <<-STR + + + + +key1 +1 +key2 +2 + + +STR + + expected_no_envelope = <<-STR + +key1 +1 +key2 +2 + +STR + assert_equal expected_no_envelope, output_plist_node + assert_equal expected_with_envelope, output_plist_dump_with_envelope + assert_equal expected_no_envelope, output_plist_dump_no_envelope + + hsh.save_plist('test.plist', indent: nil) + output_plist_file = File.read('test.plist') + assert_equal expected_with_envelope, output_plist_file + File.unlink('test.plist') + end end -- cgit v1.2.1 From 0a44713c1d6575aa4d6021349a4a3f277a3038da Mon Sep 17 00:00:00 2001 From: Yen-Nan Lin Date: Tue, 1 Aug 2017 10:36:44 +0800 Subject: Use options hash instead of keyword arguments to support Ruby 1.8 & 1.9 --- lib/plist/generator.rb | 50 ++++++++++++++++++++++++++++---------------------- test/test_generator.rb | 10 +++++----- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lib/plist/generator.rb b/lib/plist/generator.rb index 7a5b8d5..fb67f67 100644 --- a/lib/plist/generator.rb +++ b/lib/plist/generator.rb @@ -22,16 +22,18 @@ module Plist # # For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below. module Emit - DEFAULT_INDENT = "\t".freeze + DEFAULT_INDENT = "\t" # Helper method for injecting into classes. Calls Plist::Emit.dump with +self+. - def to_plist(envelope = true, indent: DEFAULT_INDENT) - return Plist::Emit.dump(self, envelope, indent: indent) + def to_plist(envelope = true, options = {}) + options = { :indent => DEFAULT_INDENT }.merge(options) + return Plist::Emit.dump(self, envelope, options) end # Helper method for injecting into classes. Calls Plist::Emit.save_plist with +self+. - def save_plist(filename, indent: DEFAULT_INDENT) - Plist::Emit.save_plist(self, filename, indent: indent) + def save_plist(filename, options = {}) + options = { :indent => DEFAULT_INDENT }.merge(options) + Plist::Emit.save_plist(self, filename, options) end # The following Ruby classes are converted into native plist types: @@ -42,8 +44,9 @@ module Plist # +IO+ and +StringIO+ objects are encoded and placed in elements; other objects are Marshal.dump'ed unless they implement +to_plist_node+. # # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment. - def self.dump(obj, envelope = true, indent: DEFAULT_INDENT) - output = plist_node(obj, indent: indent) + def self.dump(obj, envelope = true, options = {}) + options = { :indent => DEFAULT_INDENT }.merge(options) + output = plist_node(obj, options) output = wrap(output) if envelope @@ -51,14 +54,16 @@ module Plist end # Writes the serialized object's plist to the specified filename. - def self.save_plist(obj, filename, indent: DEFAULT_INDENT) + def self.save_plist(obj, filename, options = {}) + options = { :indent => DEFAULT_INDENT }.merge(options) File.open(filename, 'wb') do |f| - f.write(obj.to_plist(indent: indent)) + f.write(obj.to_plist(true, options)) end end private - def self.plist_node(element, indent: DEFAULT_INDENT) + def self.plist_node(element, options = {}) + options = { :indent => DEFAULT_INDENT }.merge(options) output = '' if element.respond_to? :to_plist_node @@ -69,8 +74,8 @@ module Plist if element.empty? output << "\n" else - output << tag('array', indent: indent) { - element.collect {|e| plist_node(e)} + output << tag('array', '', options) { + element.collect {|e| plist_node(e, options)} } end when Hash @@ -81,22 +86,22 @@ module Plist element.keys.sort_by{|k| k.to_s }.each do |k| v = element[k] - inner_tags << tag('key', CGI.escapeHTML(k.to_s), indent: indent) - inner_tags << plist_node(v, indent: indent) + inner_tags << tag('key', CGI.escapeHTML(k.to_s), options) + inner_tags << plist_node(v, options) end - output << tag('dict', indent: indent) { + output << tag('dict', '', options) { inner_tags } end when true, false output << "<#{element}/>\n" when Time - output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), indent: indent) + output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), options) when Date # also catches DateTime - output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'), indent: indent) + output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'), options) when String, Symbol, Integer, Float - output << tag(element_type(element), CGI.escapeHTML(element.to_s), indent: indent) + output << tag(element_type(element), CGI.escapeHTML(element.to_s), options) when IO, StringIO element.rewind contents = element.read @@ -106,12 +111,12 @@ module Plist # because b64encode is b0rked and ignores the length arg. data = "\n" Base64.encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } - output << tag('data', data, indent: indent) + output << tag('data', data, options) else output << comment('The element below contains a Ruby object which has been serialized with Marshal.dump.') data = "\n" Base64.encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } - output << tag('data', data, indent: indent) + output << tag('data', data, options) end end @@ -122,11 +127,12 @@ module Plist return "\n" end - def self.tag(type, contents = '', indent: DEFAULT_INDENT, &block) + def self.tag(type, contents = '', options = {}, &block) + options = { :indent => DEFAULT_INDENT }.merge(options) out = nil if block_given? - out = IndentedString.new(indent) + out = IndentedString.new(options[:indent]) out << "<#{type}>" out.raise_indent diff --git a/test/test_generator.rb b/test/test_generator.rb index 71974dd..c93073b 100644 --- a/test/test_generator.rb +++ b/test/test_generator.rb @@ -72,10 +72,10 @@ class TestGenerator < Test::Unit::TestCase end def test_custom_indent - hsh = { key1: 1, 'key2' => 2 } - output_plist_node = Plist::Emit.plist_node(hsh, indent: nil) - output_plist_dump_with_envelope = Plist::Emit.dump(hsh, indent: nil) - output_plist_dump_no_envelope = Plist::Emit.dump(hsh, false, indent: nil) + hsh = { :key1 => 1, 'key2' => 2 } + output_plist_node = Plist::Emit.plist_node(hsh, :indent => nil) + output_plist_dump_with_envelope = Plist::Emit.dump(hsh, true, :indent => nil) + output_plist_dump_no_envelope = Plist::Emit.dump(hsh, false, :indent => nil) expected_with_envelope = <<-STR @@ -102,7 +102,7 @@ STR assert_equal expected_with_envelope, output_plist_dump_with_envelope assert_equal expected_no_envelope, output_plist_dump_no_envelope - hsh.save_plist('test.plist', indent: nil) + hsh.save_plist('test.plist', :indent => nil) output_plist_file = File.read('test.plist') assert_equal expected_with_envelope, output_plist_file File.unlink('test.plist') -- cgit v1.2.1 From 923dd1ce5d6859abe123d4b847620f8c1e5bfe7e Mon Sep 17 00:00:00 2001 From: Yen-Nan Lin Date: Tue, 22 Aug 2017 16:41:49 +0800 Subject: Add description of support custom indent to Changelog and README --- CHANGELOG.rdoc | 1 + README.rdoc | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 57618f0..efe0157 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -5,6 +5,7 @@ https://github.com/patsplat/plist/compare/v3.3.0...HEAD * Your contribution here! +* Support custom indent string (https://github.com/patsplat/plist/pull/44) === 3.3.0 (2017-04-28) diff --git a/README.rdoc b/README.rdoc index 5803a39..220c45a 100644 --- a/README.rdoc +++ b/README.rdoc @@ -112,6 +112,23 @@ When you attempt to serialize a +MyFancyString+ object, the +to_plist_node+ meth If for whatever reason you can't add this method, your object will be serialized with Marshal.dump instead. +==== Custom indent + +You can customize the default indent foramt (default format is tab) or specify the indent format on each serialization. For example, if you want to reduce size of plist output, you can set the indent to nil. + +An example to change default indent format: + + Plist::Emit::DEFAULT_INDENT = nil + +An example to specify indent format on dump: + + Plist::Emit.dump({:foo => :bar}, false) + => "\n\tfoo\n\tbar\n\n" + + Plist::Emit.dump({:foo => :bar}, false, :indent => nil) + => "\nfoo\nbar\n\n" + + == Links [Rubygems] https://rubygems.org/gems/plist -- cgit v1.2.1