firestone 0.0.2 → 0.0.3

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.
data/README.md CHANGED
@@ -36,7 +36,8 @@ or
36
36
 
37
37
  This currently only works on OSX.
38
38
 
39
- ### Create a new Firefox profile with a couple of custom preferences
39
+ ### Manage Firefox profiles
40
+ #### Profile Creation:
40
41
 
41
42
  require 'firefox'
42
43
  p = Firefox::Profile.create('./newprofile')
@@ -51,6 +52,15 @@ This currently only works on OSX.
51
52
  This will create a new firefox profile in `./newprofile`. It will populate the new profile's preferences with the values provided.
52
53
  If the given folder does not exist it will create it.
53
54
 
55
+ #### Profile Deletion:
56
+
57
+ require 'firefox'
58
+ Firefox::Profile.destroy('./newprofile')
59
+ # returns true if profile found and deleted, otherwise returns fase
60
+
61
+ This will delete all profile data and de-register the profile.
62
+ This is a non-reversible, destructive operation
63
+
54
64
  ## Suggestions, comments, bugs, whatever
55
65
  Feel free to use Issues to submit bugs, suggestions or feature requests.
56
66
 
@@ -1,5 +1,6 @@
1
- require "#{File.dirname(File.realpath(__FILE__))}/fondue"
2
- %W{ version base prefs profile addons installer }.each { |r| require "#{File.dirname(File.realpath(__FILE__))}/firefox/#{r}" }
1
+ %W{ fondue inifile }.each { |r| require File.join(File.dirname(File.realpath(__FILE__)),r) }
2
+ %W{ version base prefs profile addons installer }.each { |r| require File.join(File.dirname(File.realpath(__FILE__)),'firefox',r) }
3
+
3
4
  module Firefox
4
5
  def self.install!
5
6
  installer = Firefox::Installer.new(Firefox::Base.platform(RUBY_PLATFORM))
@@ -1,4 +1,7 @@
1
1
  module Firefox
2
+ # TODO: extension listing using <profile>/extensions.sqlite
3
+ # TODO: extension installation using zip/zip
4
+ # TODO: extension removal
2
5
  class Addons < Fondue::HashClass
3
6
  attr_accessor :path, :addons
4
7
 
@@ -19,7 +19,7 @@ module Firefox
19
19
  when :linux
20
20
  @bin_path = '/usr/bin/firefox'
21
21
  else
22
- raise UnsupportedOSError.new("I don't really know what OS you're on, sorry")
22
+ raise UnsupportedOSError, "I don't really know what OS you're on, sorry"
23
23
  end
24
24
  end
25
25
 
@@ -23,19 +23,66 @@ module Firefox
23
23
  # This is the right way to initialize a new profile.
24
24
  # It checks if the given directory exists, creates it if not
25
25
  def create path
26
+ ini = inifile.dup
26
27
  FileUtils.mkdir_p(path) unless File.directory?(path)
27
28
  FileUtils.touch(%W[prefs user].map { |f| File.join(path,"#{f}.js") })
28
- response = call_ff_create(path)
29
- if response =~ /Error/
30
- raise ProfileInitializationError, response
31
- else
32
- self.new(path)
29
+
30
+ last_entry_num = ini.sections.last.scan(/Profile([0-9]*)/).first.first.to_i
31
+ ini["Profile#{last_entry_num+1}"] = {
32
+ 'Name' => File.split(path).last,
33
+ 'IsRelative' => 0,
34
+ 'Path' => path
35
+ }
36
+ ini.write
37
+ new(path)
38
+ end
39
+
40
+ def destroy name
41
+ deleted = false
42
+ # delete profile form registry if name matches
43
+ inifile.sections.each do |section|
44
+ if inifile[section]['Name'] == name.to_s
45
+ FileUtils.rm_rf inifile[section]['Path']
46
+ inifile.delete_section(section)
47
+ deleted = true
48
+ end
49
+ end
50
+
51
+ # if we just deleted a profile, we need to renumber all other profiles
52
+ # so that firefox doesn't get confused and cries
53
+ if deleted
54
+ new_content = {}
55
+ i = 0
56
+ inifile.sections.each do |s|
57
+ if s =~ /Profile[0-9]*/
58
+ new_content["Profile#{i}"] = inifile[s]
59
+ inifile.delete_section(s)
60
+ i+=1
61
+ end
62
+ end
63
+ inifile.merge!(new_content)
33
64
  end
65
+
66
+ inifile.write
67
+ deleted
34
68
  end
35
69
 
36
- def call_ff_create path
37
- name = File.split(path).last
38
- %x[#{Base.bin_path} -CreateProfile \"#{name} #{File.realpath(path)}\" 2>&1]
70
+ def inifile reload = false
71
+ @inifile = IniFile.load(File.join(inifile_path(Base.platform(RUBY_PLATFORM)),'profiles.ini')) if @inifile.nil? or reload
72
+ @inifile
73
+ end
74
+
75
+ def inifile_path os
76
+ case os
77
+ when :osx
78
+ File.join('/','Users',ENV['USER'],'Library','Application Support','Firefox')
79
+ when :linux
80
+ File.join('/','home',ENV['USER'],'.mozilla','firefox')
81
+ when :win
82
+ File.join('C:','Documents and Settings',ENV['USER'],'Application Data','Mozilla','Firefox')
83
+ else
84
+ raise UnsupportedOSError, "I don't really know what OS you're on, sorry"
85
+ end
39
86
  end
40
87
  end
41
88
  end
@@ -1,3 +1,3 @@
1
1
  module Firefox
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,4 +1,4 @@
1
- %W{ version hash_class }.each { |r| require "#{File.dirname(File.realpath(__FILE__))}/fondue/#{r}" }
1
+ %W{ version hash_class }.each { |r| require File.join(File.dirname(File.realpath(__FILE__)),'fondue',r) }
2
2
 
3
3
  module Fondue
4
4
  end
@@ -0,0 +1,553 @@
1
+ #encoding: UTF-8
2
+ require 'strscan'
3
+ # [AC] Stolen from https://github.com/TwP/inifile/blob/master/lib/inifile.rb
4
+ # [AC] Had to tweak it a wee bit, as Firefox is very picky about ini file formatting
5
+ #
6
+ # This class represents the INI file and can be used to parse, modify,
7
+ # and write INI files.
8
+ #
9
+ class IniFile
10
+ include Enumerable
11
+
12
+ class Error < StandardError; end
13
+ VERSION = '2.0.2'
14
+
15
+ # Public: Open an INI file and load the contents.
16
+ #
17
+ # filename - The name of the fiel as a String
18
+ # opts - The Hash of options (default: {})
19
+ # :comment - String containing the comment character(s)
20
+ # :parameter - String used to separate parameter and value
21
+ # :encoding - Encoding String for reading / writing (Ruby 1.9)
22
+ # :escape - Boolean used to control character escaping
23
+ # :default - The String name of the default global section
24
+ #
25
+ # Examples
26
+ #
27
+ # IniFile.load('file.ini')
28
+ # #=> IniFile instance
29
+ #
30
+ # IniFile.load('does/not/exist.ini')
31
+ # #=> nil
32
+ #
33
+ # Returns an IniFile intsnace or nil if the file could not be opened.
34
+ #
35
+ def self.load( filename, opts = {} )
36
+ return unless File.file? filename
37
+ new(opts.merge(:filename => filename))
38
+ end
39
+
40
+ # Get and set the filename
41
+ attr_accessor :filename
42
+
43
+ # Get and set the encoding (Ruby 1.9)
44
+ attr_accessor :encoding
45
+
46
+ # Enable or disable character escaping
47
+ attr_accessor :escape
48
+
49
+ # Public: Create a new INI file from the given content String which
50
+ # contains the INI file lines. If the content are omitted, then the
51
+ # :filename option is used to read in the content of the INI file. If
52
+ # neither the content for a filename is provided then an empty INI file is
53
+ # created.
54
+ #
55
+ # content - The String containing the INI file contents
56
+ # opts - The Hash of options (default: {})
57
+ # :comment - String containing the comment character(s)
58
+ # :parameter - String used to separate parameter and value
59
+ # :encoding - Encoding String for reading / writing (Ruby 1.9)
60
+ # :escape - Boolean used to control character escaping
61
+ # :default - The String name of the default global section
62
+ # :filename - The filename as a String
63
+ #
64
+ # Examples
65
+ #
66
+ # IniFile.new
67
+ # #=> an empty IniFile instance
68
+ #
69
+ # IniFile.new( "[global]\nfoo=bar" )
70
+ # #=> an IniFile instance
71
+ #
72
+ # IniFile.new( :filename => 'file.ini', :encoding => 'UTF-8' )
73
+ # #=> an IniFile instance
74
+ #
75
+ # IniFile.new( "[global]\nfoo=bar", :comment => '#' )
76
+ # #=> an IniFile instance
77
+ #
78
+ def initialize( content = nil, opts = {} )
79
+ opts, content = content, nil if Hash === content
80
+
81
+ @content = content
82
+
83
+ @comment = opts.fetch(:comment, ';#')
84
+ @param = opts.fetch(:parameter, '=')
85
+ @encoding = opts.fetch(:encoding, nil)
86
+ @escape = opts.fetch(:escape, true)
87
+ @default = opts.fetch(:default, 'global')
88
+ @filename = opts.fetch(:filename, nil)
89
+
90
+ @ini = Hash.new {|h,k| h[k] = Hash.new}
91
+
92
+ if @content then parse!
93
+ elsif @filename then read
94
+ end
95
+ end
96
+
97
+ # Public: Write the contents of this IniFile to the file system. If left
98
+ # unspecified, the currently configured filename and encoding will be used.
99
+ # Otherwise the filename and encoding can be specified in the options hash.
100
+ #
101
+ # opts - The default options Hash
102
+ # :filename - The filename as a String
103
+ # :encoding - The encoding as a String (Ruby 1.9)
104
+ #
105
+ # Returns this IniFile instance.
106
+ #
107
+ def write( opts = {} )
108
+ filename = opts.fetch(:filename, @filename)
109
+ encoding = opts.fetch(:encoding, @encoding)
110
+ mode = (RUBY_VERSION >= '1.9' && encoding) ?
111
+ "w:#{encoding.to_s}" :
112
+ 'w'
113
+
114
+ File.open(filename, mode) do |f|
115
+ @ini.each do |section,hash|
116
+ f.puts "[#{section}]"
117
+ hash.each {|param,val| f.puts "#{param}#{@param}#{escape_value val}"}
118
+ f.puts
119
+ end
120
+ end
121
+
122
+ self
123
+ end
124
+ alias :save :write
125
+
126
+ # Public: Read the contents of the INI file from the file system and replace
127
+ # and set the state of this IniFile instance. If left unspecified the
128
+ # currently configured filename and encoding will be used when reading from
129
+ # the file system. Otherwise the filename and encoding can be specified in
130
+ # the options hash.
131
+ #
132
+ # opts - The default options Hash
133
+ # :filename - The filename as a String
134
+ # :encoding - The encoding as a String (Ruby 1.9)
135
+ #
136
+ # Returns this IniFile instance if the read was successful; nil is returned
137
+ # if the file could not be read.
138
+ #
139
+ def read( opts = {} )
140
+ filename = opts.fetch(:filename, @filename)
141
+ encoding = opts.fetch(:encoding, @encoding)
142
+ return unless File.file? filename
143
+
144
+ mode = (RUBY_VERSION >= '1.9' && encoding) ?
145
+ "r:#{encoding.to_s}" :
146
+ 'r'
147
+ fd = File.open(filename, mode)
148
+ @content = fd.read
149
+
150
+ parse!
151
+ self
152
+ ensure
153
+ fd.close if fd && !fd.closed?
154
+ end
155
+ alias :restore :read
156
+
157
+ # Returns this IniFile converted to a String.
158
+ #
159
+ def to_s
160
+ s = []
161
+ @ini.each do |section,hash|
162
+ s << "[#{section}]"
163
+ hash.each {|param,val| s << "#{param} #{@param} #{escape_value val}"}
164
+ s << ""
165
+ end
166
+ s.join("\n")
167
+ end
168
+
169
+ # Returns this IniFile converted to a Hash.
170
+ #
171
+ def to_h
172
+ @ini.dup
173
+ end
174
+
175
+ # Public: Creates a copy of this inifile with the entries from the
176
+ # other_inifile merged into the copy.
177
+ #
178
+ # other - The other IniFile.
179
+ #
180
+ # Returns a new IniFile.
181
+ #
182
+ def merge( other )
183
+ self.dup.merge!(other)
184
+ end
185
+
186
+ # Public: Merges other_inifile into this inifile, overwriting existing
187
+ # entries. Useful for having a system inifile with user over-ridable settings
188
+ # elsewhere.
189
+ #
190
+ # other - The other IniFile.
191
+ #
192
+ # Returns this IniFile.
193
+ #
194
+ def merge!( other )
195
+ my_keys = @ini.keys
196
+ other_keys =
197
+ case other
198
+ when IniFile; other.instance_variable_get(:@ini).keys
199
+ when Hash; other.keys
200
+ else raise "cannot merge contents from '#{other.class.name}'" end
201
+
202
+ (my_keys & other_keys).each do |key|
203
+ @ini[key].merge!(other[key])
204
+ end
205
+
206
+ (other_keys - my_keys).each do |key|
207
+ @ini[key] = other[key]
208
+ end
209
+
210
+ self
211
+ end
212
+
213
+ # Public: Yield each INI file section, parameter, and value in turn to the
214
+ # given block.
215
+ #
216
+ # block - The block that will be iterated by the each method. The block will
217
+ # be passed the current section and the parameter / value pair.
218
+ #
219
+ # Examples
220
+ #
221
+ # inifile.each do |section, parameter, value|
222
+ # puts "#{parameter} = #{value} [in section - #{section}]"
223
+ # end
224
+ #
225
+ # Returns this IniFile.
226
+ #
227
+ def each
228
+ return unless block_given?
229
+ @ini.each do |section,hash|
230
+ hash.each do |param,val|
231
+ yield section, param, val
232
+ end
233
+ end
234
+ self
235
+ end
236
+
237
+ # Public: Yield each section in turn to the given block.
238
+ #
239
+ # block - The block that will be iterated by the each method. The block will
240
+ # be passed the current section as a Hash.
241
+ #
242
+ # Examples
243
+ #
244
+ # inifile.each_section do |section|
245
+ # puts section.inspect
246
+ # end
247
+ #
248
+ # Returns this IniFile.
249
+ #
250
+ def each_section
251
+ return unless block_given?
252
+ @ini.each_key {|section| yield section}
253
+ self
254
+ end
255
+
256
+ # Public: Remove a section identified by name from the IniFile.
257
+ #
258
+ # section - The section name as a String.
259
+ #
260
+ # Returns the deleted section Hash.
261
+ #
262
+ def delete_section( section )
263
+ @ini.delete section.to_s
264
+ end
265
+
266
+ # Public: Get the section Hash by name. If the section does not exist, then
267
+ # it will be created.
268
+ #
269
+ # section - The section name as a String.
270
+ #
271
+ # Examples
272
+ #
273
+ # inifile['global']
274
+ # #=> global section Hash
275
+ #
276
+ # Returns the Hash of parameter/value pairs for this section.
277
+ #
278
+ def []( section )
279
+ return nil if section.nil?
280
+ @ini[section.to_s]
281
+ end
282
+
283
+ # Public: Set the section to a hash of parameter/value pairs.
284
+ #
285
+ # section - The section name as a String.
286
+ # value - The Hash of parameter/value pairs.
287
+ #
288
+ # Examples
289
+ #
290
+ # inifile['tenderloin'] = { 'gritty' => 'yes' }
291
+ # #=> { 'gritty' => 'yes' }
292
+ #
293
+ # Returns the value Hash.
294
+ #
295
+ def []=( section, value )
296
+ @ini[section.to_s] = value
297
+ end
298
+
299
+ # Public: Create a Hash containing only those INI file sections whose names
300
+ # match the given regular expression.
301
+ #
302
+ # regex - The Regexp used to match section names.
303
+ #
304
+ # Examples
305
+ #
306
+ # inifile.match(/^tree_/)
307
+ # #=> Hash of matching sections
308
+ #
309
+ # Return a Hash containing only those sections that match the given regular
310
+ # expression.
311
+ #
312
+ def match( regex )
313
+ @ini.dup.delete_if { |section, _| section !~ regex }
314
+ end
315
+
316
+ # Public: Check to see if the IniFile contains the section.
317
+ #
318
+ # section - The section name as a String.
319
+ #
320
+ # Returns true if the section exists in the IniFile.
321
+ #
322
+ def has_section?( section )
323
+ @ini.has_key? section.to_s
324
+ end
325
+
326
+ # Returns an Array of section names contained in this IniFile.
327
+ #
328
+ def sections
329
+ @ini.keys
330
+ end
331
+
332
+ # Public: Freeze the state of this IniFile object. Any attempts to change
333
+ # the object will raise an error.
334
+ #
335
+ # Returns this IniFile.
336
+ #
337
+ def freeze
338
+ super
339
+ @ini.each_value {|h| h.freeze}
340
+ @ini.freeze
341
+ self
342
+ end
343
+
344
+ # Public: Mark this IniFile as tainted -- this will traverse each section
345
+ # marking each as tainted.
346
+ #
347
+ # Returns this IniFile.
348
+ #
349
+ def taint
350
+ super
351
+ @ini.each_value {|h| h.taint}
352
+ @ini.taint
353
+ self
354
+ end
355
+
356
+ # Public: Produces a duplicate of this IniFile. The duplicate is independent
357
+ # of the original -- i.e. the duplicate can be modified without changing the
358
+ # original. The tainted state of the original is copied to the duplicate.
359
+ #
360
+ # Returns a new IniFile.
361
+ #
362
+ def dup
363
+ other = super
364
+ other.instance_variable_set(:@ini, Hash.new {|h,k| h[k] = Hash.new})
365
+ @ini.each_pair {|s,h| other[s].merge! h}
366
+ other.taint if self.tainted?
367
+ other
368
+ end
369
+
370
+ # Public: Produces a duplicate of this IniFile. The duplicate is independent
371
+ # of the original -- i.e. the duplicate can be modified without changing the
372
+ # original. The tainted state and the frozen state of the original is copied
373
+ # to the duplicate.
374
+ #
375
+ # Returns a new IniFile.
376
+ #
377
+ def clone
378
+ other = dup
379
+ other.freeze if self.frozen?
380
+ other
381
+ end
382
+
383
+ # Public: Compare this IniFile to some other IniFile. For two INI files to
384
+ # be equivalent, they must have the same sections with the same parameter /
385
+ # value pairs in each section.
386
+ #
387
+ # other - The other IniFile.
388
+ #
389
+ # Returns true if the INI files are equivalent and false if they differ.
390
+ #
391
+ def eql?( other )
392
+ return true if equal? other
393
+ return false unless other.instance_of? self.class
394
+ @ini == other.instance_variable_get(:@ini)
395
+ end
396
+ alias :== :eql?
397
+
398
+
399
+ private
400
+
401
+ # Parse the ini file contents. This will clear any values currently stored
402
+ # in the ini hash.
403
+ #
404
+ def parse!
405
+ return unless @content
406
+
407
+ string = ''
408
+ property = ''
409
+
410
+ @ini.clear
411
+ @_line = nil
412
+ @_section = nil
413
+
414
+ scanner = StringScanner.new(@content)
415
+ until scanner.eos?
416
+
417
+ # keep track of the current line for error messages
418
+ @_line = scanner.check(%r/\A.*$/) if scanner.bol?
419
+
420
+ # look for escaped special characters \# \" etc
421
+ if scanner.scan(%r/\\([\[\]#{@param}#{@comment}"])/)
422
+ string << scanner[1]
423
+
424
+ # look for quoted strings
425
+ elsif scanner.scan(%r/"/)
426
+ quote = scanner.scan_until(/(?:\A|[^\\])"/)
427
+ parse_error('Unmatched quote') if quote.nil?
428
+
429
+ quote.chomp!('"')
430
+ string << quote
431
+
432
+ # look for comments, empty strings, end of lines
433
+ elsif scanner.skip(%r/\A\s*(?:[#{@comment}].*)?$/)
434
+ string << scanner.getch unless scanner.eos?
435
+
436
+ process_property(property, string)
437
+
438
+ # look for the separator between property name and value
439
+ elsif scanner.scan(%r/#{@param}/)
440
+ if property.empty?
441
+ property = string.strip
442
+ string.slice!(0, string.length)
443
+ else
444
+ parse_error
445
+ end
446
+
447
+ # look for the start of a new section
448
+ elsif scanner.scan(%r/\A\s*\[([^\]]+)\]/)
449
+ @_section = @ini[scanner[1]]
450
+
451
+ # otherwise scan and store characters till we hit the start of some
452
+ # special section like a quote, newline, comment, etc.
453
+ else
454
+ tmp = scanner.scan_until(%r/([\n"#{@param}#{@comment}] | \z | \\[\[\]#{@param}#{@comment}"])/mx)
455
+ parse_error if tmp.nil?
456
+
457
+ len = scanner[1].length
458
+ tmp.slice!(tmp.length - len, len)
459
+
460
+ scanner.pos = scanner.pos - len
461
+ string << tmp
462
+ end
463
+ end
464
+
465
+ process_property(property, string)
466
+ end
467
+
468
+ # Store the property / value pair in the currently active section. This
469
+ # method checks for continuation of the value to the next line.
470
+ #
471
+ # property - The property name as a String.
472
+ # value - The property value as a String.
473
+ #
474
+ # Returns nil.
475
+ #
476
+ def process_property( property, value )
477
+ value.chomp!
478
+ return if property.empty? and value.empty?
479
+ return if value.sub!(%r/\\\s*\z/, '')
480
+
481
+ property.strip!
482
+ value.strip!
483
+
484
+ parse_error if property.empty?
485
+
486
+ current_section[property.dup] = unescape_value(value.dup)
487
+
488
+ property.slice!(0, property.length)
489
+ value.slice!(0, value.length)
490
+
491
+ nil
492
+ end
493
+
494
+ # Returns the current section Hash.
495
+ #
496
+ def current_section
497
+ @_section ||= @ini[@default]
498
+ end
499
+
500
+ # Raise a parse error using the given message and appending the current line
501
+ # being parsed.
502
+ #
503
+ # msg - The message String to use.
504
+ #
505
+ # Raises IniFile::Error
506
+ #
507
+ def parse_error( msg = 'Could not parse line' )
508
+ raise Error, "#{msg}: #{@_line.inspect}"
509
+ end
510
+
511
+ # Unescape special characters found in the value string. This will convert
512
+ # escaped null, tab, carriage return, newline, and backslash into their
513
+ # literal equivalents.
514
+ #
515
+ # value - The String value to unescape.
516
+ #
517
+ # Returns the unescaped value.
518
+ #
519
+ def unescape_value( value )
520
+ return value unless @escape
521
+
522
+ value = value.to_s
523
+ value.gsub!(%r/\\[0nrt\\]/) { |char|
524
+ case char
525
+ when '\0'; "\0"
526
+ when '\n'; "\n"
527
+ when '\r'; "\r"
528
+ when '\t'; "\t"
529
+ when '\\\\'; "\\"
530
+ end
531
+ }
532
+ value
533
+ end
534
+
535
+ # Escape special characters.
536
+ #
537
+ # value - The String value to escape.
538
+ #
539
+ # Returns the escaped value.
540
+ #
541
+ def escape_value( value )
542
+ return value unless @escape
543
+
544
+ value = value.to_s.dup
545
+ value.gsub!(%r/\\([0nrt])/, '\\\\\1')
546
+ value.gsub!(%r/\n/, '\n')
547
+ value.gsub!(%r/\r/, '\r')
548
+ value.gsub!(%r/\t/, '\t')
549
+ value.gsub!(%r/\0/, '\0')
550
+ value
551
+ end
552
+
553
+ end # IniFile
@@ -0,0 +1,33 @@
1
+ [General]
2
+ StartWithLastProfile=1
3
+
4
+ [Profile0]
5
+ Name=default
6
+ IsRelative=1
7
+ Path=Profiles/yoyoma.default
8
+
9
+ [Profile1]
10
+ Name=2220
11
+ IsRelative=0
12
+ Path=./spec/files/profiles/2220
13
+
14
+ [Profile2]
15
+ Name=2221
16
+ IsRelative=0
17
+ Path=./spec/files/profiles/2221
18
+
19
+ [Profile3]
20
+ Name=2240
21
+ IsRelative=0
22
+ Path=./spec/files/profiles/2240
23
+
24
+ [Profile4]
25
+ Name=2241
26
+ IsRelative=0
27
+ Path=./spec/files/profiles/2241
28
+
29
+ [Profile5]
30
+ Name=2242
31
+ IsRelative=0
32
+ Path=./spec/files/profiles/2242
33
+
@@ -2,26 +2,70 @@ require 'spec_helper'
2
2
 
3
3
  describe Firefox::Profile do
4
4
  before { @path = './spec/files/' }
5
+ subject { Firefox::Profile }
5
6
 
6
- context '#register_profile' do
7
+ context '#inifile_path' do
8
+ it { subject.inifile_path(:osx).should eq("/Users/#{ENV['USER']}/Library/Application Support/Firefox") }
9
+ it { subject.inifile_path(:win).should eq("C:/Documents and Settings/#{ENV['USER']}/Application Data/Mozilla/Firefox") }
10
+ it { subject.inifile_path(:linux).should eq("/home/#{ENV['USER']}/.mozilla/firefox") }
11
+ end
12
+
13
+ context '#inifile' do
14
+ before { Firefox::Profile.stub(:inifile_path).and_return('./spec/files/') }
15
+
16
+ it { subject.inifile.should be_a(IniFile) }
17
+ it { subject.inifile['General']['StartWithLastProfile'].should eq("1") }
18
+ end
19
+
20
+ context '#create' do
7
21
  before {
22
+ @inifile = './spec/files/profiles.ini'
23
+ @old_inifile = File.read(@inifile)
8
24
  @path = './spec/files/testprofile'
9
- Firefox::Profile.stub(:call_ff_create).and_return("Success: created profile 'test /Users/achilles/Scripts/serpclicker/profiles/' at '/Users/achilles/Scripts/serpclicker/profiles/prefs.js'")
25
+ Firefox::Profile.stub(:inifile_path).and_return('./spec/files/')
26
+ }
27
+ after {
28
+ FileUtils.rm_rf @path
29
+ File.open(@inifile,'w') {|f| f.write(@old_inifile)}
10
30
  }
11
- after { FileUtils.rm_rf @path }
12
31
  subject { Firefox::Profile.create(@path) }
13
32
 
14
33
  it { subject.should be_a(Firefox::Profile) }
15
- it "saves prefs on save" do
34
+
35
+ it 'saves prefs on save' do
16
36
  subject.prefs.merge!({ :test => true })
17
37
  subject.save!
18
38
 
19
39
  n = Firefox::Profile.new(@path)
20
40
  n.prefs.prefs.should eq({ "test" => true })
21
41
  end
42
+
43
+ it 'updates ini file' do
44
+ subject
45
+ inifile = IniFile.load(@inifile)
46
+ inifile.sections.last.should eq('Profile6')
47
+ inifile['Profile6']['Name'].should eq('testprofile')
48
+ end
22
49
  end
23
50
 
24
- subject { Firefox::Profile.new(@path) }
25
- it { subject.prefs.should be_a(Firefox::Prefs) }
26
- it { subject.addons.should be_a(Firefox::Addons) }
51
+ context "#destroy" do
52
+ before {
53
+ @inifile = './spec/files/profiles.ini'
54
+ @old_inifile = File.read(@inifile)
55
+ Firefox::Profile.stub(:inifile_path).and_return('./spec/files/') }
56
+ after { File.open(@inifile,'w') {|f| f.write(@old_inifile)} }
57
+
58
+ it 'should reorder profiles' do
59
+ subject.destroy(2240).should eq(true)
60
+ subject.inifile.sections.size.should eq(6)
61
+ subject.inifile.sections.include?('Profile5').should eq(false)
62
+ end
63
+ end
64
+
65
+ context 'associations' do
66
+ subject { Firefox::Profile.new(@path) }
67
+
68
+ it { subject.prefs.should be_a(Firefox::Prefs) }
69
+ it { subject.addons.should be_a(Firefox::Addons) }
70
+ end
27
71
  end
data/test.rb ADDED
@@ -0,0 +1,3 @@
1
+ require './lib/firefox'
2
+ i = Firefox::Installer.new(:osx,nil,'18.0.2', :dmg => '/var/folders/9p/n54h7qmx57351_by82lh77d40000gn/T/firefox.dmg')
3
+ i.install!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firestone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-17 00:00:00.000000000Z
12
+ date: 2013-02-18 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: progressbar
16
- requirement: &2161532540 !ruby/object:Gem::Requirement
16
+ requirement: &2157028880 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2161532540
24
+ version_requirements: *2157028880
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2161532120 !ruby/object:Gem::Requirement
27
+ requirement: &2157028460 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2161532120
35
+ version_requirements: *2157028460
36
36
  description: A collection of Firefox automation and programmatic management scripts
37
37
  in Ruby
38
38
  email:
@@ -57,12 +57,15 @@ files:
57
57
  - lib/fondue.rb
58
58
  - lib/fondue/hash_class.rb
59
59
  - lib/fondue/version.rb
60
+ - lib/inifile.rb
60
61
  - spec/addons_spec.rb
61
62
  - spec/files/prefs.js
63
+ - spec/files/profiles.ini
62
64
  - spec/hash_class_spec.rb
63
65
  - spec/prefs_spec.rb
64
66
  - spec/profile_spec.rb
65
67
  - spec/spec_helper.rb
68
+ - test.rb
66
69
  homepage: http://humbuckercode.co.uk/licks/gems/firestone
67
70
  licenses: []
68
71
  post_install_message:
@@ -91,6 +94,7 @@ summary: A collection of Firefox automation and programmatic management scripts
91
94
  test_files:
92
95
  - spec/addons_spec.rb
93
96
  - spec/files/prefs.js
97
+ - spec/files/profiles.ini
94
98
  - spec/hash_class_spec.rb
95
99
  - spec/prefs_spec.rb
96
100
  - spec/profile_spec.rb