fontcustom 1.1.0.pre → 1.1.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/TODO.md +20 -5
- data/lib/fontcustom.rb +42 -4
- data/lib/fontcustom/cli.rb +65 -25
- data/lib/fontcustom/generator/font.rb +26 -26
- data/lib/fontcustom/generator/template.rb +29 -30
- data/lib/fontcustom/options.rb +207 -23
- data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +9 -9
- data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +19 -19
- data/lib/fontcustom/templates/_fontcustom-rails.scss +28 -0
- data/lib/fontcustom/templates/_fontcustom.scss +11 -11
- data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +9 -9
- data/lib/fontcustom/templates/fontcustom-bootstrap.css +19 -19
- data/lib/fontcustom/templates/fontcustom-preview.html +34 -7
- data/lib/fontcustom/templates/fontcustom.css +11 -11
- data/lib/fontcustom/templates/fontcustom.yml +11 -6
- data/lib/fontcustom/util.rb +38 -159
- data/lib/fontcustom/version.rb +1 -1
- data/lib/fontcustom/watcher.rb +16 -14
- data/spec/fixtures/generators/.fontcustom-data-corrupted +18 -0
- data/spec/fixtures/generators/fontcustom.yml +1 -0
- data/spec/fixtures/{util/fontcustom.yml → options/any-file-name.yml} +0 -0
- data/spec/fixtures/{util → options}/config-is-in-dir/fontcustom.yml +0 -0
- data/spec/fixtures/options/fontcustom-empty.yml +1 -0
- data/spec/fixtures/{util → options}/fontcustom-malformed.yml +0 -0
- data/spec/fixtures/options/fontcustom.yml +1 -0
- data/spec/fixtures/options/no-config-here/.gitkeep +0 -0
- data/spec/fixtures/{util → options}/rails-like/config/fontcustom.yml +0 -0
- data/spec/fontcustom/generator/font_spec.rb +31 -15
- data/spec/fontcustom/generator/template_spec.rb +20 -18
- data/spec/fontcustom/options_spec.rb +428 -0
- data/spec/fontcustom/util_spec.rb +38 -336
- data/spec/fontcustom/watcher_spec.rb +7 -2
- data/spec/spec_helper.rb +1 -2
- metadata +23 -13
- data/lib/fontcustom/actions.rb +0 -28
- data/spec/fontcustom/actions_spec.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50485d013861fa91e2ae86ed2741630ad3b285ff
|
4
|
+
data.tar.gz: 5b30887bf48000f2faf726c1995fea6f2bcb9ba8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac4e3f33a7748d4884995e8bdd3725dfb71bc51c1642ebd4d57fd1c9a2ac695c6b1775c73d276aec5b973bbd4316c0bf2b304a5f5939ce3cc798b57dfb36af5e
|
7
|
+
data.tar.gz: a768dd51e28c43b2f3634ecb0b082edde1510a34f563c1598a4ee9add5e8708ab2141d867284c99759ee8628e8d47bff2190572932fcbe6e3d3611fbbc9f36e4
|
data/TODO.md
CHANGED
@@ -1,6 +1,21 @@
|
|
1
|
-
|
1
|
+
# 1.1.0 TODO
|
2
2
|
|
3
|
-
*
|
4
|
-
*
|
5
|
-
|
6
|
-
*
|
3
|
+
* Investigate initial update to .fontcustom-data
|
4
|
+
* Verify all templates work
|
5
|
+
|
6
|
+
* Include pull requests
|
7
|
+
* Allow absolute paths
|
8
|
+
* Abstract path expansion into Util
|
9
|
+
* Improve paths in messages (wrap in ticks)
|
10
|
+
* Improve error messages in Watcher and Fontcustom.rb
|
11
|
+
|
12
|
+
# Maybe
|
13
|
+
|
14
|
+
* Option to set icon canvas size (auto, string, or hash)
|
15
|
+
* `fontcustom clean`
|
16
|
+
|
17
|
+
* Have error messages `say_status` themselves?
|
18
|
+
* Change outputed filenames to reflect font name
|
19
|
+
* On install hook / message to remind about installing fontforge
|
20
|
+
* --silent instead of (or alongside?) --verbose
|
21
|
+
* Configure colors for thor say
|
data/lib/fontcustom.rb
CHANGED
@@ -1,21 +1,59 @@
|
|
1
1
|
require "fontcustom/version"
|
2
|
-
require "fontcustom/options"
|
3
2
|
require "fontcustom/error"
|
3
|
+
require "fontcustom/options"
|
4
4
|
require "fontcustom/util"
|
5
|
-
require "fontcustom/actions"
|
6
5
|
require "fontcustom/generator/font"
|
7
6
|
require "fontcustom/generator/template"
|
7
|
+
require "thor/core_ext/hash_with_indifferent_access"
|
8
8
|
|
9
9
|
module Fontcustom
|
10
10
|
##
|
11
11
|
# Clean Ruby API to workaround Thor
|
12
12
|
def compile(options)
|
13
|
-
opts = Fontcustom::
|
13
|
+
opts = Fontcustom::Options.new options
|
14
14
|
Fontcustom::Generator::Font.start [opts]
|
15
15
|
Fontcustom::Generator::Template.start [opts]
|
16
16
|
rescue Fontcustom::Error => e
|
17
17
|
puts "ERROR: #{e.message}"
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
def gem_lib
|
21
|
+
File.expand_path(File.join(File.dirname(__FILE__), "fontcustom"))
|
22
|
+
end
|
23
|
+
|
24
|
+
module_function :compile, :gem_lib
|
25
|
+
|
26
|
+
##
|
27
|
+
# These are used in Thor CLI but overridden when the Options class is built
|
28
|
+
EXAMPLE_OPTIONS = {
|
29
|
+
:project_root => "`pwd`",
|
30
|
+
:output => "PROJECT_ROOT/FONT_NAME"
|
31
|
+
}
|
32
|
+
|
33
|
+
##
|
34
|
+
#
|
35
|
+
DEFAULT_OPTIONS = Thor::CoreExt::HashWithIndifferentAccess.new({
|
36
|
+
:project_root => Dir.pwd,
|
37
|
+
:input => nil,
|
38
|
+
:output => nil,
|
39
|
+
:config => nil,
|
40
|
+
:data_cache => nil,
|
41
|
+
:templates => %w|css preview|,
|
42
|
+
:font_name => "fontcustom",
|
43
|
+
:file_hash => true,
|
44
|
+
:css_prefix => "icon-",
|
45
|
+
:preprocessor_path => "",
|
46
|
+
:debug => false,
|
47
|
+
:verbose => true
|
48
|
+
})
|
49
|
+
|
50
|
+
DATA_MODEL = Thor::CoreExt::HashWithIndifferentAccess.new({
|
51
|
+
:fonts => [],
|
52
|
+
:templates => [],
|
53
|
+
:glyphs => [],
|
54
|
+
:paths => {
|
55
|
+
:css_to_fonts => "",
|
56
|
+
:preprocessor_to_fonts => ""
|
57
|
+
}
|
58
|
+
})
|
21
59
|
end
|
data/lib/fontcustom/cli.rb
CHANGED
@@ -5,53 +5,93 @@ require "fontcustom/watcher"
|
|
5
5
|
|
6
6
|
module Fontcustom
|
7
7
|
class CLI < Thor
|
8
|
-
include
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
class_option :
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
class_option :
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
class_option :
|
8
|
+
include Actions
|
9
|
+
|
10
|
+
default_task :show_help
|
11
|
+
|
12
|
+
class_option :project_root, :aliases => "-r", :type => :string,
|
13
|
+
:desc => "The root context for any relative paths (INPUT, OUTPUT, CONFIG).",
|
14
|
+
:default => EXAMPLE_OPTIONS[:project_root]
|
15
|
+
|
16
|
+
class_option :output, :aliases => "-o", :type => :string,
|
17
|
+
:desc => "Where generated files are saved. Can be fine-tuned if a configuration file is used.",
|
18
|
+
:default => EXAMPLE_OPTIONS[:output]
|
19
|
+
|
20
|
+
class_option :config, :aliases => "-c", :type => :string,
|
21
|
+
:desc => "Optional configuration file. PROJECT_ROOT/fontcustom.yml and PROJECT_ROOT/config/fontcustom.yml are loaded automatically."
|
22
|
+
|
23
|
+
class_option :data_cache, :aliases => "-d", :type => :string,
|
24
|
+
:desc => "Optional path to `.fontcustom-data`. Used for garbage collection."
|
25
|
+
|
26
|
+
class_option :templates, :aliases => "-t", :type => :array,
|
27
|
+
:desc => "Space-delinated array of templates to generate alongside fonts.",
|
28
|
+
:enum => %w|preview css scss scss-rails bootstrap bootstrap-scss bootstrap-ie7 bootstrap-ie7-scss|,
|
29
|
+
:default => DEFAULT_OPTIONS[:templates]
|
30
|
+
|
31
|
+
class_option :font_name, :aliases => "-f", :type => :string,
|
32
|
+
:desc => "Set the font's name.",
|
33
|
+
:default => DEFAULT_OPTIONS[:font_name]
|
34
|
+
|
35
|
+
class_option :css_prefix, :aliases => "-p", :type => :string,
|
36
|
+
:desc => "Prefix for each glyph's CSS class.",
|
37
|
+
:default => DEFAULT_OPTIONS[:css_prefix]
|
38
|
+
|
39
|
+
class_option :preprocessor_path, :aliases => "-s", :type => :string,
|
40
|
+
:desc => "Special path used in CSS proprocessor templates."
|
41
|
+
|
42
|
+
# TODO make this negative (no file hash)
|
43
|
+
class_option :file_hash, :type => :boolean,
|
44
|
+
:desc => "Option to generate font files with asset-busting hashes.",
|
45
|
+
:default => DEFAULT_OPTIONS[:file_hash]
|
46
|
+
|
47
|
+
class_option :debug, :type => :boolean,
|
48
|
+
:desc => "Display debug messages from fontforge.",
|
49
|
+
:default => DEFAULT_OPTIONS[:debug]
|
50
|
+
|
51
|
+
class_option :verbose, :type => :boolean,
|
52
|
+
:desc => "Display verbose messages.",
|
53
|
+
:default => DEFAULT_OPTIONS[:verbose]
|
21
54
|
|
22
55
|
# Required for Thor::Actions#template
|
23
56
|
def self.source_root
|
24
|
-
File.join Fontcustom
|
57
|
+
File.join Fontcustom.gem_lib, "templates"
|
25
58
|
end
|
26
59
|
|
27
|
-
desc "compile [INPUT] [OPTIONS]", "Generates webfonts and
|
60
|
+
desc "compile [INPUT] [OPTIONS]", "Generates webfonts and templates from *.svg and *.eps files in INPUT. Default: `pwd`"
|
28
61
|
def compile(input = nil)
|
29
62
|
opts = options.merge :input => input
|
30
|
-
opts = Fontcustom::
|
63
|
+
opts = Fontcustom::Options.new(opts)
|
31
64
|
Fontcustom::Generator::Font.start [opts]
|
32
65
|
Fontcustom::Generator::Template.start [opts]
|
33
66
|
rescue Fontcustom::Error => e
|
34
|
-
|
67
|
+
say_status :error, e.message
|
35
68
|
end
|
36
69
|
|
37
|
-
desc "watch [INPUT] [OPTIONS]", "Watches INPUT for changes and regenerates files automatically. Ctrl + C to stop."
|
38
|
-
method_option :skip_first, :
|
70
|
+
desc "watch [INPUT] [OPTIONS]", "Watches INPUT for changes and regenerates files automatically. Ctrl + C to stop. Default: `pwd`"
|
71
|
+
method_option :skip_first, :type => :boolean,
|
72
|
+
:desc => "Skip the initial compile upon watching.",
|
73
|
+
:default => false
|
39
74
|
def watch(input = nil)
|
40
75
|
opts = options.merge :input => input, :skip_first => !! options[:skip_first]
|
41
|
-
opts = Fontcustom::
|
76
|
+
opts = Fontcustom::Options.new(opts)
|
42
77
|
Fontcustom::Watcher.new(opts).watch
|
43
78
|
rescue Fontcustom::Error => e
|
44
|
-
|
79
|
+
say_status :error, e.message
|
45
80
|
end
|
46
81
|
|
47
|
-
desc "config [DIR]", "
|
82
|
+
desc "config [DIR]", "Generates an annotated configuration file (fontcustom.yml) in DIR. Default: `pwd`"
|
48
83
|
def config(dir = Dir.pwd)
|
49
84
|
template "fontcustom.yml", File.join(dir, "fontcustom.yml")
|
50
85
|
end
|
51
86
|
|
52
|
-
desc "
|
53
|
-
|
54
|
-
|
87
|
+
desc "hidden", "hidden", :hide => true
|
88
|
+
method_option :version, :aliases => "-v", :type => :boolean, :default => false
|
89
|
+
def show_help
|
90
|
+
if options[:version]
|
91
|
+
puts "fontcustom-#{Fontcustom::VERSION}"
|
92
|
+
else
|
93
|
+
help
|
94
|
+
end
|
55
95
|
end
|
56
96
|
end
|
57
97
|
end
|
@@ -1,35 +1,36 @@
|
|
1
1
|
require "json"
|
2
2
|
require "thor"
|
3
3
|
require "thor/group"
|
4
|
+
require "thor/actions"
|
4
5
|
require "thor/core_ext/hash_with_indifferent_access"
|
5
6
|
|
6
7
|
module Fontcustom
|
7
8
|
module Generator
|
8
9
|
class Font < Thor::Group
|
9
|
-
include
|
10
|
+
include Util
|
11
|
+
include Thor::Actions
|
10
12
|
|
11
|
-
# Instead of passing each option individually we're passing the entire options hash as an argument.
|
13
|
+
# Instead of passing each option individually we're passing the entire options hash as an argument.
|
12
14
|
# This is DRYier, easier to maintain.
|
13
|
-
argument :opts
|
15
|
+
argument :opts
|
14
16
|
|
15
17
|
def prepare_output_dirs
|
16
|
-
dirs = opts
|
18
|
+
dirs = opts.output.values.uniq
|
17
19
|
dirs.each do |dir|
|
18
20
|
unless File.directory? dir
|
19
|
-
empty_directory dir, :verbose => opts
|
21
|
+
empty_directory dir, :verbose => opts.verbose
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
def get_data
|
25
|
-
|
26
|
-
if File.exists? datafile
|
27
|
+
if File.exists? opts.data_cache
|
27
28
|
begin
|
28
|
-
data = File.read
|
29
|
+
data = File.read opts.data_cache
|
29
30
|
data = JSON.parse(data, :symbolize_names => true) unless data.empty?
|
30
31
|
@data = data.is_a?(Hash) ? Thor::CoreExt::HashWithIndifferentAccess.new(data) : Fontcustom::DATA_MODEL.dup
|
31
32
|
rescue JSON::ParserError
|
32
|
-
raise Fontcustom::Error, "
|
33
|
+
raise Fontcustom::Error, "#{opts.data_cache} is corrupted. Fix the JSON or delete the file to start from scratch."
|
33
34
|
end
|
34
35
|
else
|
35
36
|
@data = Fontcustom::DATA_MODEL.dup
|
@@ -40,38 +41,39 @@ module Fontcustom
|
|
40
41
|
return if @data[:fonts].empty?
|
41
42
|
begin
|
42
43
|
deleted = []
|
43
|
-
@data[:fonts].each do |file|
|
44
|
+
@data[:fonts].each do |file|
|
44
45
|
remove_file file, :verbose => false
|
45
46
|
deleted << file
|
46
47
|
end
|
47
48
|
ensure
|
48
49
|
@data[:fonts] = @data[:fonts] - deleted
|
49
50
|
json = JSON.pretty_generate @data
|
50
|
-
|
51
|
-
|
52
|
-
append_to_file file, json, :verbose => false
|
53
|
-
say_changed :removed, deleted
|
51
|
+
overwrite_file opts.data_cache, json
|
52
|
+
say_changed :delete, deleted
|
54
53
|
end
|
55
54
|
end
|
56
|
-
|
55
|
+
|
57
56
|
def generate
|
58
57
|
# TODO align option naming conventions with python script
|
59
58
|
# TODO remove name arg if default is already set in python (or rm from python)
|
60
|
-
name = opts
|
61
|
-
hash = opts
|
62
|
-
cmd = "fontforge -script #{Fontcustom
|
59
|
+
name = opts.font_name ? " --name " + opts.font_name : ""
|
60
|
+
hash = opts.file_hash ? "" : " --nohash"
|
61
|
+
cmd = "fontforge -script #{Fontcustom.gem_lib}/scripts/generate.py #{opts.input[:vectors]} #{opts.output[:fonts] + name + hash} 2>&1"
|
63
62
|
|
64
63
|
output = `#{cmd}`.split("\n")
|
65
64
|
@json = output[3] # JSON
|
65
|
+
|
66
|
+
# fontforge wrongly returns the following error message if only a single glyph.
|
67
|
+
# We can strip it out and ignore it.
|
66
68
|
if @json == 'Warning: Font contained no glyphs'
|
67
69
|
@json = output[4]
|
68
|
-
output = output[5..-1]
|
70
|
+
output = output[5..-1]
|
69
71
|
else
|
70
72
|
@json = output[3]
|
71
|
-
output = output[4..-1]
|
73
|
+
output = output[4..-1]
|
72
74
|
end
|
73
75
|
|
74
|
-
if opts
|
76
|
+
if opts.debug
|
75
77
|
shell.say "DEBUG: (raw output from fontforge)"
|
76
78
|
shell.say output
|
77
79
|
end
|
@@ -85,18 +87,16 @@ module Fontcustom
|
|
85
87
|
@json = JSON.parse(@json, :symbolize_names => true)
|
86
88
|
@data.merge! @json
|
87
89
|
@data[:glyphs].map! { |glyph| glyph.gsub(/\W/, "-") }
|
88
|
-
@data[:fonts].map! { |font| File.join(
|
90
|
+
@data[:fonts].map! { |font| File.join(opts.output[:fonts], font) }
|
89
91
|
end
|
90
92
|
|
91
93
|
def announce_files
|
92
|
-
say_changed :
|
94
|
+
say_changed :create, @data[:fonts]
|
93
95
|
end
|
94
96
|
|
95
97
|
def save_data
|
96
98
|
json = JSON.pretty_generate @data
|
97
|
-
|
98
|
-
clear_file(file)
|
99
|
-
append_to_file file, json, :verbose => false
|
99
|
+
overwrite_file opts.data_cache, json
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
@@ -2,11 +2,13 @@ require "json"
|
|
2
2
|
require "pathname"
|
3
3
|
require "thor"
|
4
4
|
require "thor/group"
|
5
|
+
require "thor/actions"
|
5
6
|
|
6
7
|
module Fontcustom
|
7
8
|
module Generator
|
8
9
|
class Template < Thor::Group
|
9
|
-
include
|
10
|
+
include Util
|
11
|
+
include Thor::Actions
|
10
12
|
|
11
13
|
# Instead of passing each option individually we're passing the entire options hash as an argument.
|
12
14
|
# This is DRYier, easier to maintain.
|
@@ -14,19 +16,18 @@ module Fontcustom
|
|
14
16
|
|
15
17
|
# Required for Thor::Actions#template
|
16
18
|
def self.source_root
|
17
|
-
File.join Fontcustom
|
19
|
+
File.join Fontcustom.gem_lib, "templates"
|
18
20
|
end
|
19
21
|
|
20
22
|
def get_data
|
21
|
-
|
22
|
-
|
23
|
-
@data = JSON.parse(File.read(data), :symbolize_names => true)
|
23
|
+
if File.exists? opts.data_cache
|
24
|
+
@data = JSON.parse(File.read(opts.data_cache), :symbolize_names => true)
|
24
25
|
else
|
25
|
-
raise Fontcustom::Error, "
|
26
|
+
raise Fontcustom::Error, "#{relative_to_root(opts.data_cache)} is required to generate templates, but I couldn't find it."
|
26
27
|
end
|
27
28
|
rescue JSON::ParserError
|
28
29
|
# Catches both empty and and malformed files
|
29
|
-
raise Fontcustom::Error, "
|
30
|
+
raise Fontcustom::Error, "#{relative_to_root(opts.data_cache)} is empty or corrupted. Try deleting the file and running Fontcustom::Generator::Font again to regenerate the data file. Old generated files may need to be deleted manually."
|
30
31
|
end
|
31
32
|
|
32
33
|
def reset_output
|
@@ -40,54 +41,52 @@ module Fontcustom
|
|
40
41
|
ensure
|
41
42
|
@data[:templates] = @data[:templates] - deleted
|
42
43
|
json = JSON.pretty_generate @data
|
43
|
-
|
44
|
-
|
45
|
-
append_to_file file, json, :verbose => false
|
46
|
-
say_changed :removed, deleted
|
44
|
+
overwrite_file opts.data_cache, json
|
45
|
+
say_changed :delete, deleted
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
50
49
|
def make_relative_paths
|
51
50
|
name = File.basename @data[:fonts].first, File.extname(@data[:fonts].first)
|
52
|
-
fonts = Pathname.new opts
|
53
|
-
css = Pathname.new opts
|
54
|
-
preview = Pathname.new opts
|
51
|
+
fonts = Pathname.new opts.output[:fonts]
|
52
|
+
css = Pathname.new opts.output[:css]
|
53
|
+
preview = Pathname.new opts.output[:preview]
|
55
54
|
@data[:paths][:css_to_fonts] = File.join fonts.relative_path_from(css).to_s, name
|
56
|
-
@data[:paths][:
|
57
|
-
@data[:paths][:preprocessor_to_fonts] = if opts
|
58
|
-
File.join opts
|
59
|
-
else
|
55
|
+
@data[:paths][:preview_to_fonts] = File.join fonts.relative_path_from(preview).to_s, name
|
56
|
+
@data[:paths][:preprocessor_to_fonts] = if opts.preprocessor_path != ""
|
57
|
+
File.join opts.preprocessor_path, name
|
58
|
+
else
|
60
59
|
@data[:paths][:css_to_fonts]
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
64
63
|
def generate
|
65
|
-
@
|
64
|
+
@glyphs = @data[:glyphs]
|
65
|
+
@font_path = @data[:paths][:css_to_fonts]
|
66
|
+
@font_path_pre = @data[:paths][:preprocessor_to_fonts]
|
66
67
|
begin
|
67
68
|
created = []
|
68
|
-
opts
|
69
|
+
opts.templates.each do |source|
|
69
70
|
name = File.basename source
|
70
|
-
ext = File.extname
|
71
|
-
target = if opts
|
72
|
-
File.join opts
|
71
|
+
ext = File.extname source
|
72
|
+
target = if opts.output.keys.include? name
|
73
|
+
File.join opts.output[name], name
|
73
74
|
elsif %w|.css .scss .sass .less .stylus|.include? ext
|
74
|
-
File.join opts
|
75
|
+
File.join opts.output[:css], name
|
75
76
|
elsif name == "fontcustom-preview.html"
|
76
|
-
File.join opts
|
77
|
+
File.join opts.output[:preview], name
|
77
78
|
else
|
78
|
-
File.join opts
|
79
|
+
File.join opts.output[:fonts], name
|
79
80
|
end
|
80
81
|
|
81
82
|
template source, target, :verbose => false
|
82
83
|
created << target
|
83
84
|
end
|
84
85
|
ensure
|
86
|
+
say_changed :create, created
|
85
87
|
@data[:templates] = (@data[:templates] + created).uniq
|
86
88
|
json = JSON.pretty_generate @data
|
87
|
-
|
88
|
-
clear_file(file)
|
89
|
-
append_to_file file, json, :verbose => false
|
90
|
-
say_changed :created, created
|
89
|
+
overwrite_file opts.data_cache, json
|
91
90
|
end
|
92
91
|
end
|
93
92
|
end
|