plist4r 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+
2
+ module Plist4r::Backend::Plutil
3
+ # maybe this should be a helper, included by other backends
4
+ class << self
5
+ # use tempfile to write out data
6
+ # convert it into target format
7
+
8
+ # plutil -convert xml1 @filename
9
+ # plutil -convert binary1 @filename
10
+ # next step is not supported
11
+
12
+ # def validate
13
+ # system "plutil #{@filename}"
14
+ # end
15
+ end
16
+ end
17
+
18
+
19
+
@@ -0,0 +1,191 @@
1
+
2
+ require 'plist4r/backend'
3
+
4
+ module Plist4r::Backend::RubyCocoa
5
+ class << self
6
+ def ruby_cocoa_wrapper_rb
7
+ @ruby_cocoa_wrapper_rb ||= <<-'EOC'
8
+ #!/usr/bin/ruby
9
+
10
+ include_endpath = "plist4r/mixin/ordered_hash.rb"
11
+ raise "No path given to include #{include_endpath}" unless ARGV[0] && ARGV[0] =~ /#{include_endpath}$/
12
+ ordered_hash_rb = ARGV[0]
13
+
14
+ require ordered_hash_rb
15
+
16
+ class OSX::NSObject
17
+ def to_ruby
18
+ case self
19
+ when OSX::NSDate
20
+ self.to_time
21
+ when OSX::NSCFBoolean
22
+ self.boolValue
23
+ when OSX::NSNumber
24
+ self.integer? ? self.to_i : self.to_f
25
+ when OSX::NSString
26
+ self.to_s
27
+ when OSX::NSAttributedString
28
+ self.string.to_s
29
+ when OSX::NSArray
30
+ self.to_a.map { |x| x.is_a?(OSX::NSObject) ? x.to_ruby : x }
31
+ when OSX::NSDictionary
32
+ h = ::ActiveSupport::OrderedHash.new
33
+ self.each do |x, y|
34
+ x = x.to_ruby if x.is_a?(OSX::NSObject)
35
+ y = y.to_ruby if y.is_a?(OSX::NSObject)
36
+ h[x] = y
37
+ end
38
+ h
39
+ else
40
+ self
41
+ end
42
+ end
43
+ end
44
+
45
+ module Plist
46
+ def to_xml hash
47
+ # to_plist defaults to NSPropertyListXMLFormat_v1_0
48
+ x = hash.to_ruby.to_plist
49
+ puts "#{x}"
50
+ end
51
+ def to_binary hash
52
+ # Here 200 == NSPropertyListBinaryFormat_v1_0
53
+ x = hash.to_ruby.to_plist 200
54
+ puts "#{x}"
55
+ end
56
+
57
+ def open filename
58
+ plist_dict = ::OSX::NSDictionary.dictionaryWithContentsOfFile(filename)
59
+ puts "#{plist_dict.to_ruby.inspect}"
60
+ end
61
+
62
+ def save hash, filename, file_format
63
+ case file_format.to_sym
64
+ when :xml
65
+ x = hash.to_plist # NSPropertyListXMLFormat_v1_0
66
+ when :binary
67
+ x = hash.to_plist 200 # NSPropertyListBinaryFormat_v1_0
68
+ when :next_step
69
+ raise "File format #{file_format.inspect} is not supported by RubyCocoa"
70
+ else
71
+ raise "File format #{file_format.inspect} not recognised"
72
+ end
73
+ File.open(filename,'w'){ |o| o << x }
74
+ end
75
+ end
76
+
77
+ class RubyCocoaWrapper
78
+ include Plist
79
+
80
+ def exec stdin
81
+ begin
82
+ require 'osx/cocoa'
83
+ instance_eval stdin
84
+ exit 0
85
+ rescue LoadError
86
+ raise $!
87
+ rescue
88
+ raise $!
89
+ end
90
+ end
91
+ end
92
+
93
+ stdin = $stdin.read()
94
+ wrapper = RubyCocoaWrapper.new()
95
+ wrapper.exec stdin
96
+ EOC
97
+ end
98
+
99
+ def ruby_cocoa_exec stdin_str
100
+ rubycocoa_framework = "/System/Library/Frameworks/RubyCocoa.framework"
101
+ raise "RubyCocoa Framework not found. Searched in: #{rubycocoa_framework}" unless File.exists? rubycocoa_framework
102
+
103
+ require 'tempfile'
104
+ require 'plist4r/mixin/popen4'
105
+
106
+ if @rb_script && File.exists?(@rb_script.path)
107
+ @rb_script ||= Tempfile.new("ruby_cocoa_wrapper.rb") do |o|
108
+ o << ruby_cocoa_rb
109
+ end
110
+ File.chmod 0755, @rb_script.path
111
+ end
112
+
113
+ cmd = @rb_script.path
114
+ ordered_hash_rb = File.join(File.dirname(__FILE__), "..", "mixin", "ordered_hash.rb")
115
+
116
+ pid, stdin, stdout, stderr = Popen4::popen4 [cmd, ordered_hash_rb]
117
+
118
+ stdin.puts stdin_str
119
+
120
+ stdin.close
121
+ ignored, status = Process::waitpid2 pid
122
+
123
+ stdout_result = stdout.read.strip
124
+ stderr_result = stderr.read.strip
125
+
126
+ return [cmd, status, stdout_result, stderr_result]
127
+ end
128
+
129
+ def from_string plist, string
130
+ raise "method not implemented yet (unfinished)"
131
+ end
132
+
133
+ def to_xml plist
134
+ hash = plist.to_hash
135
+ result = ruby_cocoa_exec "to_xml(\"#{hash}\")"
136
+ case result[1].exitstatus
137
+ when 0
138
+ xml_string = eval result[2]
139
+ return xml_string
140
+ else
141
+ $stderr.puts result[3]
142
+ raise "Error executing #{result[0]}. See stderr for more information"
143
+ end
144
+ end
145
+
146
+ def to_binary plist
147
+ hash = plist.to_hash
148
+ result = ruby_cocoa_exec "to_binary(\"#{hash}\")"
149
+ case result[1].exitstatus
150
+ when 0
151
+ binary_string = eval result[2]
152
+ return binary_string
153
+ else
154
+ $stderr.puts result[3]
155
+ raise "Error executing #{result[0]}. See stderr for more information"
156
+ end
157
+ end
158
+
159
+ def open plist
160
+ filename = plist.filename
161
+ result = ruby_cocoa_exec "open(\"#{filename}\")"
162
+ case result[1].exitstatus
163
+ when 0
164
+ hash = eval result[2]
165
+ plist.import_hash hash
166
+ else
167
+ $stderr.puts result[3]
168
+ raise "Error executing #{result[0]}. See stderr for more information"
169
+ end
170
+ file_format = Plist4r.file_detect_format filename
171
+ plist.file_format = file_format
172
+ return plist
173
+ end
174
+
175
+ def save hash, filename, file_format
176
+ filename = plist.filename_path
177
+ file_format = plist.file_format || Config[:default_format]
178
+ raise "#{self} - cant save file of format #{file_format}" unless [:xml,:binary].include? file_format
179
+
180
+ hash = plist.to_hash
181
+ result = ruby_cocoa_exec "save(\"#{hash}\",#{filename},#{file_format})"
182
+ case result[1].exitstatus
183
+ when 0
184
+ return true
185
+ else
186
+ raise "Error executing #{result[0]}. See stderr for more information"
187
+ end
188
+ end
189
+ end
190
+ end
191
+
@@ -0,0 +1,18 @@
1
+
2
+ require 'plist4r/mixin/mixlib_config'
3
+
4
+ class Plist4r::Config
5
+ extend Mixlib::Config
6
+
7
+ backends [
8
+ Plist4r::Backend::RubyCocoa,
9
+ Plist4r::Backend::Haml,
10
+ Plist4r::Backend::Libxml4r
11
+ ]
12
+
13
+ unsupported_keys true
14
+ raise_any_failure false
15
+ deafult_format :xml
16
+ default_path nil
17
+ end
18
+
@@ -0,0 +1,7 @@
1
+
2
+ require 'plist4r/mixin/object'
3
+ require 'plist4r/mixin/string'
4
+ require 'plist4r/mixin/ordered_hash'
5
+ require 'plist4r/mixin/popen4'
6
+ require 'plist4r/mixin/data_methods'
7
+
@@ -0,0 +1,128 @@
1
+ # class_attributes.rb - Class Attributes
2
+ # A Feature-complete alternative to @@
3
+
4
+ class Object
5
+ def deep_clone; Marshal::load(Marshal.dump(self)); end
6
+ end
7
+
8
+ module ClassAttributes
9
+
10
+ def cattr(*args, &block)
11
+ (class << self; self; end).class_eval do
12
+ attr_accessor *args
13
+ end
14
+ @cattr ||= []
15
+ @cattr.concat(args)
16
+ end
17
+
18
+ def iattr(*args, &block)
19
+ (class << self; self; end).class_eval do
20
+ attr_accessor *args
21
+ end
22
+ @iattr ||= []
23
+ @iattr.concat(args)
24
+ end
25
+
26
+ def oattr(*args, &block)
27
+ (class << self; self; end).class_eval do
28
+ attr_accessor *args
29
+ end
30
+ @oattr ||= []
31
+ @oattr.concat(args)
32
+ end
33
+
34
+ def oattr_i(*args, &block)
35
+ (class << self; self; end).class_eval do
36
+ attr_accessor *args
37
+ end
38
+ @oattr_i ||= []
39
+ @oattr_i.concat(args)
40
+ end
41
+
42
+ def co_attr(*args, &block)
43
+ cattr(*args,&block)
44
+ oattr(*args,&block)
45
+ end
46
+
47
+ def co_attr_i(*args, &block)
48
+ iattr(*args,&block)
49
+ oattr_i(*args,&block)
50
+ end
51
+
52
+ alias_method :class_inherited_attribute_shared, :cattr
53
+ alias_method :class_inherited_attribute_independant, :iattr
54
+
55
+ alias_method :object_inherited_attribute_shared, :oattr
56
+ alias_method :object_inherited_attribute_independant, :oattr_i
57
+
58
+ alias_method :class_and_object_shared_inherited_attribute, :co_attr
59
+ alias_method :class_and_object_independant_inherited_attribute, :co_attr_i
60
+
61
+ def inherited(subclass)
62
+ super(subclass) if respond_to?('super')
63
+ iattr.each do |a|
64
+ # puts "a=#{a}"
65
+ subclass.send("#{a}=", send(a).deep_clone)
66
+ subclass.send("iattr", a.to_sym)
67
+ end
68
+ cattr.each do |a|
69
+ subclass.send("#{a}=", send(a))
70
+ subclass.send("cattr", a.to_sym)
71
+ end
72
+ oattr.each do |a|
73
+ subclass.send("oattr", a.to_sym)
74
+ end
75
+ oattr_i.each do |a|
76
+ subclass.send("oattr_i", a.to_sym)
77
+ end
78
+ subclass.send(:inherit) if subclass.respond_to?('inherit')
79
+ end
80
+
81
+ def inherit(*args, &block)
82
+ super if respond_to?('super')
83
+ end
84
+ end
85
+
86
+ module ObjectPreInitialize
87
+ private
88
+ def pre_initialize(*args, &block)
89
+ super if respond_to?('super')
90
+
91
+ class_attrs = self.class.cattr + self.class.iattr
92
+
93
+ self.class.oattr.each do |a|
94
+ sac = self.class.send(a)
95
+ eval "@#{a.to_s}=sac" if class_attrs.include? a
96
+ end
97
+
98
+ self.class.oattr_i.each do |a|
99
+ sac = self.class.send(a)
100
+ eval "@#{a.to_s}=sac.deep_clone" if class_attrs.include? a
101
+ end
102
+ end
103
+
104
+ # def postinitialize(*args, &block)
105
+ # end
106
+ end
107
+
108
+ module OverloadNew
109
+ def new(*args, &block)
110
+ newObj = self.allocate
111
+ newObj.send :extend, ObjectPreInitialize
112
+ newObj.send :pre_initialize, *args, &block
113
+ newObj.send :initialize, *args, &block
114
+ # newObj.send :postinitialize, *args, &block
115
+ return newObj
116
+ end
117
+ end
118
+
119
+ def has_class_attributes
120
+ extend ClassAttributes
121
+ end
122
+
123
+ def has_class_object_attributes
124
+ extend ClassAttributes
125
+ extend OverloadNew
126
+ end
127
+
128
+
@@ -0,0 +1,63 @@
1
+
2
+ require 'plist4r/mixins/ordered_hash'
3
+
4
+ module Plst4r::DataMethods
5
+
6
+ def classes_for_key_type
7
+ {
8
+ :string => [String],
9
+ :bool => [TrueClass,FalseClass],
10
+ :integer => [Fixnum],
11
+ :array_of_strings => [Array],
12
+ :hash_of_bools => [Hash],
13
+ :hash => [Hash],
14
+ :bool_or_string_or_array_of_strings => [TrueClass,FalseClass,String,Array]
15
+ }
16
+ end
17
+
18
+ def valid_keys
19
+ {}
20
+ end
21
+
22
+ def method_missing method_symbol, *args, &blk
23
+ puts "method_missing: #{method_symbol.inspect}, args: #{args.inspect}"
24
+ valid_keys.each do |key_type, valid_keys_of_those_type|
25
+ if valid_keys_of_those_type.include?(method_symbol.to_s.camelcase)
26
+ puts "key_type = #{key_type}, method_symbol.to_s.camelcase = #{method_symbol.to_s.camelcase}, args = #{args.inspect}"
27
+ return eval("set_or_return key_type, method_symbol.to_s.camelcase, *args, &blk")
28
+ end
29
+ end
30
+ end
31
+
32
+ def validate_value key_type, key, value
33
+ unless classes_for_key_type[key_type].include? value.class
34
+ raise "Key: #{key}, value: #{value.inspect} is of type #{value.class}. Should be: #{classes_for_key_type[key_type].join ", "}"
35
+ end
36
+ case key_type
37
+ when :array_of_strings, :bool_or_string_or_array_of_strings
38
+ if value.class == Array
39
+ value.each_index do |i|
40
+ unless value[i].class == String
41
+ raise "Element: #{key}[#{i}], value: #{value[i].inspect} is of type #{value[i].class}. Should be: #{classes_for_key_type[:string].join ", "}"
42
+ end
43
+ end
44
+ end
45
+ when :hash_of_bools
46
+ value.each do |k,v|
47
+ unless [TrueClass,FalseClass].include? v.class
48
+ raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{classes_for_key_type[:bool].join ", "}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def set_or_return key_type, key, value=nil
55
+ puts "#{method_name}, key_type: #{key_type.inspect}, value: #{value.inspect}"
56
+ if value
57
+ validate_value key_type, key, value unless key_type == nil
58
+ @hash[key] = value
59
+ else
60
+ @orig[key]
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,178 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Nuo Yan (<nuo@opscode.com>)
4
+ # Author:: Christopher Brown (<cb@opscode.com>)
5
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ class Object # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
22
+ def meta_def name, &blk
23
+ (class << self; self; end).instance_eval { define_method name, &blk }
24
+ end
25
+ end
26
+
27
+ module Mixlib
28
+ module Config
29
+
30
+ def self.extended(base)
31
+ class << base; attr_accessor :configuration; end
32
+ base.configuration = Hash.new
33
+ end
34
+
35
+ # Loads a given ruby file, and runs instance_eval against it in the context of the current
36
+ # object.
37
+ #
38
+ # Raises an IOError if the file cannot be found, or is not readable.
39
+ #
40
+ # === Parameters
41
+ # <string>:: A filename to read from
42
+ def from_file(filename)
43
+ self.instance_eval(IO.read(filename), filename, 1)
44
+ end
45
+
46
+ # Pass Mixlib::Config.configure() a block, and it will yield self.configuration.
47
+ #
48
+ # === Parameters
49
+ # <block>:: A block that is sent self.configuration as its argument
50
+ def configure(&block)
51
+ block.call(self.configuration)
52
+ end
53
+
54
+ # Get the value of a configuration option
55
+ #
56
+ # === Parameters
57
+ # config_option<Symbol>:: The configuration option to return
58
+ #
59
+ # === Returns
60
+ # value:: The value of the configuration option
61
+ #
62
+ # === Raises
63
+ # <ArgumentError>:: If the configuration option does not exist
64
+ def [](config_option)
65
+ self.configuration[config_option.to_sym]
66
+ end
67
+
68
+ # Set the value of a configuration option
69
+ #
70
+ # === Parameters
71
+ # config_option<Symbol>:: The configuration option to set (within the [])
72
+ # value:: The value for the configuration option
73
+ #
74
+ # === Returns
75
+ # value:: The new value of the configuration option
76
+ def []=(config_option, value)
77
+ internal_set(config_option,value)
78
+ end
79
+
80
+ # Check if Mixlib::Config has a configuration option.
81
+ #
82
+ # === Parameters
83
+ # key<Symbol>:: The configuration option to check for
84
+ #
85
+ # === Returns
86
+ # <True>:: If the configuration option exists
87
+ # <False>:: If the configuration option does not exist
88
+ def has_key?(key)
89
+ self.configuration.has_key?(key.to_sym)
90
+ end
91
+
92
+ # Merge an incoming hash with our config options
93
+ #
94
+ # === Parameters
95
+ # hash<Hash>:: The incoming hash
96
+ #
97
+ # === Returns
98
+ # result of Hash#merge!
99
+ def merge!(hash)
100
+ self.configuration.merge!(hash)
101
+ end
102
+
103
+ # Return the set of config hash keys
104
+ #
105
+ # === Returns
106
+ # result of Hash#keys
107
+ def keys
108
+ self.configuration.keys
109
+ end
110
+
111
+ # Creates a shallow copy of the internal hash
112
+ #
113
+ # === Returns
114
+ # result of Hash#dup
115
+ def hash_dup
116
+ self.configuration.dup
117
+ end
118
+
119
+ # Internal dispatch setter, calling either the real defined method or setting the
120
+ # hash value directly
121
+ #
122
+ # === Parameters
123
+ # method_symbol<Symbol>:: Name of the method (variable setter)
124
+ # value<Object>:: Value to be set in config hash
125
+ #
126
+ def internal_set(method_symbol,value)
127
+ method_name = method_symbol.id2name
128
+ if (self.public_methods - ["[]="]).include?("#{method_name}=")
129
+ self.send("#{method_name}=", value)
130
+ else
131
+ self.configuration[method_symbol] = value
132
+ end
133
+ end
134
+
135
+ protected :internal_set
136
+
137
+ # metaprogramming to ensure that the slot for method_symbol
138
+ # gets set to value after any other logic is run
139
+ # === Parameters
140
+ # method_symbol<Symbol>:: Name of the method (variable setter)
141
+ # blk<Block>:: logic block to run in setting slot method_symbol to value
142
+ # value<Object>:: Value to be set in config hash
143
+ #
144
+ def config_attr_writer(method_symbol, &blk)
145
+ method_name = "#{method_symbol.to_s}="
146
+ meta_def method_name do |value|
147
+ self.configuration[method_symbol] = blk.call(value)
148
+ end
149
+ end
150
+
151
+ # Allows for simple lookups and setting of configuration options via method calls
152
+ # on Mixlib::Config. If there any arguments to the method, they are used to set
153
+ # the value of the configuration option. Otherwise, it's a simple get operation.
154
+ #
155
+ # === Parameters
156
+ # method_symbol<Symbol>:: The method called. Must match a configuration option.
157
+ # *args:: Any arguments passed to the method
158
+ #
159
+ # === Returns
160
+ # value:: The value of the configuration option.
161
+ #
162
+ # === Raises
163
+ # <ArgumentError>:: If the method_symbol does not match a configuration option.
164
+ def method_missing(method_symbol, *args)
165
+ num_args = args.length
166
+ # Setting
167
+ if num_args > 0
168
+ method_symbol = $1.to_sym unless (method_symbol.to_s =~ /(.+)=$/).nil?
169
+ internal_set method_symbol, (num_args == 1 ? args[0] : args)
170
+ end
171
+
172
+ # Returning
173
+ self.configuration[method_symbol]
174
+
175
+ end
176
+ end
177
+ end
178
+