diff --git a/Gemfile.lock b/Gemfile.lock index 6ac3987..142ca91 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,30 +1,49 @@ PATH remote: . specs: - csv2strings (0.2) + csv2strings (0.2.1) + google_drive (= 0.3.6) + nokogiri (= 1.5.10) thor GEM remote: http://rubygems.org/ specs: - metaclass (0.0.1) - mocha (0.10.5) - metaclass (~> 0.0.1) + faraday (0.8.8) + multipart-post (~> 1.2.0) + google_drive (0.3.6) + nokogiri (>= 1.4.4, != 1.5.2, != 1.5.1) + oauth (>= 0.3.6) + oauth2 (>= 0.5.0) + httpauth (0.2.0) + jwt (0.1.6) + multi_json (>= 1.0) multi_json (1.3.6) + multi_xml (0.5.5) + multipart-post (1.2.0) + nokogiri (1.5.10) + oauth (0.4.7) + oauth2 (0.9.2) + faraday (~> 0.8) + httpauth (~> 0.2) + jwt (~> 0.1.4) + multi_json (~> 1.0) + multi_xml (~> 0.5) + rack (~> 1.2) + rack (1.5.2) rake (0.9.2.2) simplecov (0.6.4) multi_json (~> 1.0) simplecov-html (~> 0.5.3) simplecov-html (0.5.3) test-unit (2.4.8) - thor (0.17.0) + thor (0.18.1) PLATFORMS ruby DEPENDENCIES csv2strings! - mocha rake simplecov test-unit diff --git a/README.md b/README.md index a8b21ab..f519047 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,7 @@ Run `bundle install` to install all the dependencies. Tests are done with `Test: # Todo See GitHub isssues + +# Known issues + +None diff --git a/bin/csv2strings b/bin/csv2strings index a457db1..7c3d403 100755 --- a/bin/csv2strings +++ b/bin/csv2strings @@ -1,11 +1,5 @@ #!/usr/bin/env ruby -require File.expand_path('../../lib/command', __FILE__) +require File.expand_path('../../lib/csv2strings_command', __FILE__) -if ARGV.count == 1 && ARGV[0] == "help" - Command.start(["help", "csv2strings"],{}) -else - args = ["csv2strings"] - args += ARGV - Command.start(args,{}) -end +CSV2StringsCommand.start diff --git a/bin/strings2csv b/bin/strings2csv index c220a72..a195a8d 100755 --- a/bin/strings2csv +++ b/bin/strings2csv @@ -1,10 +1,5 @@ #!/usr/bin/env ruby -require File.expand_path('../../lib/command', __FILE__) +require File.expand_path('../../lib/strings2csv_command', __FILE__) -if ARGV.count == 1 && ARGV[0] == "help" - Command.start(["help", "strings2csv"],{}) -else - args = ["strings2csv"] - args += ARGV - Command.start(args,{}) -end + +Strings2CSVCommand.start diff --git a/csv2strings.gemspec b/csv2strings.gemspec index d51590a..6019da7 100644 --- a/csv2strings.gemspec +++ b/csv2strings.gemspec @@ -1,20 +1,27 @@ Gem::Specification.new do |s| s.name = 'csv2strings' - s.version = '0.2.0' - s.date = '2013-09-02' + s.version = '0.2.1' + s.date = '2013-10-08' s.summary = "CSV to iOS Localizable.strings converter" s.description = "ruby script converts a CSV file of translations to Localizable.strings files and vice-versa" s.authors = ["François Benaiteau"] s.email = 'francois.benaiteau@gmail.com' s.homepage = 'https://github.com/netbe/CSV-to-iOS-Localizable.strings-converter' s.license = 'MIT' + s.add_dependency "thor" - s.add_dependency "fastercsv", :require => 'faster_csv' if RUBY_PLATFORM == 'ruby_19' - s.add_dependency "csv", :require => 'csv' if RUBY_PLATFORM == 'ruby_18' + + + if RUBY_VERSION < '1.9' + s.add_dependency "fastercsv" + end + s.add_dependency "nokogiri", "= 1.5.10" + s.add_dependency "google_drive", '0.3.6' s.add_development_dependency "rake" - s.add_development_dependency "mocha" + s.add_development_dependency "test-unit" s.add_development_dependency "simplecov" + s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } diff --git a/lib/command.rb b/lib/command.rb index 3decdee..ac8d62d 100644 --- a/lib/command.rb +++ b/lib/command.rb @@ -2,56 +2,31 @@ require 'yaml' require 'thor' require 'csvconverter' +require 'google_doc' class Command < Thor + include Thor::Actions + class_option :verbose, :type => :boolean - desc "CSV_FILENAME", "convert CSV file to '.strings' file" - # required options but handled in method because of options read from yaml file - method_option :filename, :type => :string, :desc => "CSV file (CSV_FILENAME) to convert from" - method_option :langs, :type => :hash, :aliases => "-L", :desc => "Languages to convert" - # optional options - method_option :excluded_states, :type => :array, :aliases => "-x", :desc => "Exclude rows with given state" - method_option :state_column, :type => :numeric, :aliases => "-s", :desc => "Position of column for state if any" - method_option :keys_column, :type => :numeric, :aliases => "-k", :desc => "Position of column for keys" - method_option :default_lang, :type => :string, :aliases => "-l", :desc => "Default language to use for empty values if any" - method_option :default_path, :type => :string, :aliases => "-p", :desc => "Path of output files" - def csv2strings(filename = nil) - unless filename || options.has_key?('filename') - puts "No value provided for required options '--filename'" - help("csv2strings") - exit + desc "csv_download", "Download Google Spreadsheet containing translations" + method_option :gd_filename, :type => :string, :required => :true, :desc => "File to download from Google Drive" + method_option :output_filename, :type => :string, :desc => "Filepath of downloaded file" + def csv_download + filename = options['gd_filename'] + gd = GoogleDoc.new + if options['output_filename'] + file_path = gd.download filename.to_s, options['output_filename'] + else + file_path = gd.download filename.to_s end - unless options.has_key?('langs') - puts "No value provided for required options '--langs'" - help("csv2strings") - exit + if file_path + say "File '#{filename}' downloaded to '#{file_path}'" + else + say "Could not download the requested file: #{filename}" end - filename ||= options['filename'] - args = options.dup - args.delete(:langs) - args.delete(:filename) - converter = CSV2Strings::Converter.new(filename, options[:langs], args) - converter.csv_to_dotstrings + file_path end - - desc "FILENAMES", "convert '.strings' files to CSV file" - # required options but handled in method because of options read from yaml file - method_option :filenames, :type => :array, :aliases => "-i", :desc => "location of strings files (FILENAMES)" - # optional options - method_option :csv_filename, :type => :string, :aliases => "-o", :desc => "location of output file" - method_option :headers, :type => :array, :aliases => "-h", :desc => "override headers of columns, default is name of input files and 'Variables' for reference" - method_option :dryrun, :type => :boolean, :aliases => "-n", :desc => "prints out content of hash without writing file" - def strings2csv - unless options.has_key?('filenames') - puts "No value provided for required options '--filenames'" - help("strings2csv") - exit - end - converter = Strings2CSV::Converter.new(options) - debug_values = converter.dotstrings_to_csv(!options[:dryrun]) - puts debug_values.inspect if options[:dryrun] - end - + private def options original_options = super @@ -60,7 +35,8 @@ def options # add default values for options here defaults["csv_filename"] = "translations.csv" unless defaults.has_key?("csv_filename") defaults["dryrun"] = false unless defaults.has_key?("dryrun") + defaults["fetch"] = false unless defaults.has_key?("fetch") defaults["keys_column"] = 0 unless defaults.has_key?("keys_column") Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options)) end -end \ No newline at end of file +end diff --git a/lib/csv2strings/converter.rb b/lib/csv2strings/converter.rb index a979f0e..687d8f6 100644 --- a/lib/csv2strings/converter.rb +++ b/lib/csv2strings/converter.rb @@ -16,7 +16,7 @@ def initialize(filename, langs, args = {}) @langs = langs if !@langs.is_a?(Hash) || @langs.size == 0 - raise "wrong format or/and languages parameter" + raise "wrong format or/and languages parameter" + @langs.inspect end @output_file = (@langs.size == 1) ? args[:output_file] : nil @@ -83,6 +83,7 @@ def csv_to_dotstrings(name = self.csv_filename) excludedCols = [] defaultCol = 0 nb_translations = 0 + CSVParserClass.foreach(name, :quote_char => '"', :col_sep =>',', :row_sep => :auto) do |row| if rowIndex == 0 @@ -115,15 +116,17 @@ def csv_to_dotstrings(name = self.csv_filename) end rowIndex += 1 end - puts "\n>>>Created #{files.size} files. Content: #{nb_translations} translations\n" + info = "Created #{files.size} files. Content: #{nb_translations} translations\n" + info += "List of created files:\n" # closing I/O files.each do |key,locale_files| locale_files.each do |file| + info += "#{file.path.to_s}\n" file.close end end - + info end # end of method end # end of class diff --git a/lib/csv2strings_command.rb b/lib/csv2strings_command.rb new file mode 100644 index 0000000..d1a25f8 --- /dev/null +++ b/lib/csv2strings_command.rb @@ -0,0 +1,44 @@ +$: << File.expand_path(File.join(File.dirname(__FILE__))) +require "command" +class CSV2StringsCommand < Command + default_task :csv2strings + + desc "CSV_FILENAME", "convert CSV file to '.strings' file" + # required options but handled in method because of options read from yaml file + method_option :filename, :type => :string, :desc => "CSV file (CSV_FILENAME) to convert from or name of file in Google Drive" + method_option :fetch, :type => :boolean, :desc => "Download file from Google Drive" + method_option :langs, :type => :hash, :aliases => "-L", :desc => "Languages to convert" + # optional options + method_option :excluded_states, :type => :array, :aliases => "-x", :desc => "Exclude rows with given state" + method_option :state_column, :type => :numeric, :aliases => "-s", :desc => "Position of column for state if any" + method_option :keys_column, :type => :numeric, :aliases => "-k", :desc => "Position of column for keys" + method_option :default_lang, :type => :string, :aliases => "-l", :desc => "Default language to use for empty values if any" + method_option :default_path, :type => :string, :aliases => "-p", :desc => "Path of output files" + def csv2strings(filename = nil) + unless filename || options.has_key?('filename') + say "No value provided for required options '--filename'" + help("csv2strings") + exit + end + + filename ||= options['filename'] + if options['fetch'] + say "Downloading file from Google Drive" + filename = invoke :csv_download, nil, {"gd_filename" => filename} + exit unless filename + end + + unless options.has_key?('langs') + say "No value provided for required options '--langs'" + help("csv2strings") + exit + end + + args = options.dup + args.delete(:langs) + args.delete(:filename) + converter = CSV2Strings::Converter.new(filename, options[:langs], args) + say converter.csv_to_dotstrings + end + +end diff --git a/lib/google_doc.rb b/lib/google_doc.rb new file mode 100644 index 0000000..406618b --- /dev/null +++ b/lib/google_doc.rb @@ -0,0 +1,25 @@ +require "google_drive" +class GoogleDoc + attr_accessor :session + + def authenticate + # will try to get token from ~/.ruby_google_drive.token + @session = GoogleDrive.saved_session + end + + def download(requested_filename, output_filename = "translations.csv") + unless @session + self.authenticate + end + result = @session.file_by_title(requested_filename) + if result.is_a? Array + file = result.first + else + file = result + end + return nil unless file + file.export_as_file(output_filename, "csv") + return output_filename + end + +end \ No newline at end of file diff --git a/lib/strings2csv_command.rb b/lib/strings2csv_command.rb new file mode 100644 index 0000000..df372d5 --- /dev/null +++ b/lib/strings2csv_command.rb @@ -0,0 +1,24 @@ +$: << File.expand_path(File.join(File.dirname(__FILE__))) +require "command" + +class Strings2CSVCommand < Command + default_task :strings2csv + + desc "FILENAMES", "convert '.strings' files to CSV file" + # required options but handled in method because of options read from yaml file + method_option :filenames, :type => :array, :aliases => "-i", :desc => "location of strings files (FILENAMES)" + # optional options + method_option :csv_filename, :type => :string, :aliases => "-o", :desc => "location of output file" + method_option :headers, :type => :array, :aliases => "-h", :desc => "override headers of columns, default is name of input files and 'Variables' for reference" + method_option :dryrun, :type => :boolean, :aliases => "-n", :desc => "prints out content of hash without writing file" + def strings2csv + unless options.has_key?('filenames') + say "No value provided for required options '--filenames'" + help("strings2csv") + exit + end + converter = Strings2CSV::Converter.new(options) + debug_values = converter.dotstrings_to_csv(!options[:dryrun]) + say debug_values.inspect if options[:dryrun] + end +end \ No newline at end of file diff --git a/test/command_test.rb b/test/command_test.rb index a6dc416..02a3d9d 100644 --- a/test/command_test.rb +++ b/test/command_test.rb @@ -1,10 +1,10 @@ -require 'test_helper' +require File.expand_path('../../lib/command', __FILE__) +require File.expand_path('../test_helper', __FILE__) -require 'command' class CommandTest < Test::Unit::TestCase def test_csv2strings_with_multiple_2_languages command = "./bin/csv2strings" - command += " test/data/test_data_multiple_langs.csv" + command += " --filename test/data/test_data_multiple_langs.csv" command += " --langs=English:en French:fr" system(command) @@ -18,7 +18,7 @@ def test_csv2strings_with_multiple_2_languages def test_csv2strings_with_default_path command = "./bin/csv2strings" - command += " test/data/test_data_multiple_langs.csv" + command += " --filename test/data/test_data_multiple_langs.csv" command += " --langs=English:en French:fr" command += " --default_path=mynewlocation" system(command) @@ -67,7 +67,7 @@ def test_strings2csv_with_output_file end def test_strings2csv_with_headers - command = "./bin/csv2strings strings2csv" + command = "./bin/strings2csv" command += " -i=test/data/test_data.strings" command += " -h=constants english" system(command) @@ -79,7 +79,7 @@ def test_strings2csv_with_headers end def test_strings2csv_with_two_files - command = "./bin/csv2strings strings2csv" + command = "./bin/strings2csv" command += " --filenames=test/data/test_en.strings test/data/test_fr.strings" command += " --headers=Constants English French" command += " -o=enfr.csv" diff --git a/test/google_doc_test.rb b/test/google_doc_test.rb new file mode 100644 index 0000000..44d7ee7 --- /dev/null +++ b/test/google_doc_test.rb @@ -0,0 +1,6 @@ +require File.expand_path('../../lib/google_doc', __FILE__) +require File.expand_path('../test_helper', __FILE__) + +class GoogleDocTest < Test::Unit::TestCase + # TODO implement test with mocks +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index c7cb7ad..f2c8b13 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,5 +8,4 @@ end require 'test/unit' -require "mocha"