diff --git a/.gitignore b/.gitignore index a3673bc..9c4e828 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,8 @@ .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* @@ -39,3 +40,12 @@ spec/reports test/tmp test/version_tmp tmp + +# Intellij IDEA +.idea +.idea_modules +*.iml +*.ipr +*.iws +*.sc +.history diff --git a/.rspec b/.rspec deleted file mode 100644 index b7afd2d..0000000 --- a/.rspec +++ /dev/null @@ -1,2 +0,0 @@ ---format Fuubar ---color diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..5dd882a --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,9 @@ +AllCops: + Exclude: + - spec/**/* + - exe/* + +#inherit_from: .rubocop_todo.yml + +Style/FileName: + Enabled: false \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9b9bfab --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +language: ruby + +sudo: false + +rvm: + - 2.1 + - 2.2.1 + - ruby-head + +cache: bundler + +before_install: + - gem install bundler -v '1.8.6' + +script: bundle exec rake test + +matrix: + allow_failures: + - rvm: ruby-head + fast_finish: true diff --git a/Rakefile b/Rakefile index 461e22a..fbff659 100644 --- a/Rakefile +++ b/Rakefile @@ -1,15 +1,31 @@ -require "bundler/gem_tasks" -require "rspec/core/rake_task" -require "yard" +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' +require 'rubocop/rake_task' +require 'yard' RSpec::Core::RakeTask.new -task :default => :spec -task :test => :spec +task test: :spec + +# Testing with rspec +RSpec::Core::RakeTask.new(:spec) do |task| + task.rspec_opts = %w(--color --format documentation) +end +task test: :spec + +# Use RuboCop to check for code/style offenses +desc 'Run RuboCop to validate/lint code' +RuboCop::RakeTask.new(:rubocop) do |task| + # don't abort rake on failure + task.fail_on_error = false +end # Documentation +desc "Generate gem documentation (same as running 'rake yard')" YARD::Rake::YardocTask.new do |t| - t.files = ['lib/**/*.rb'] # optional + t.files = %w(lib/**/*.rb) + t.stats_options = %w(--list-undoc --compact) end +task doc: :yard -# desc "Generate gem documentation (same as running 'rake yard')" -task :doc => :yard +# Default Rake task +task default: [:rubocop, :spec] diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..85e34ee --- /dev/null +++ b/bin/console @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require 'bundler/setup' +require 'faker_japanese' + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# Use Pry by default +require 'pry' +Pry.start diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..b65ed50 --- /dev/null +++ b/bin/setup @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail +IFS=$'\n\t' + +bundle install + +# Do any other automated setup that you need to do here diff --git a/faker_japanese.gemspec b/faker_japanese.gemspec index e267def..a51f131 100644 --- a/faker_japanese.gemspec +++ b/faker_japanese.gemspec @@ -4,24 +4,34 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'faker_japanese/version' Gem::Specification.new do |spec| - spec.name = "faker_japanese" - spec.version = Faker::Japanese::VERSION - spec.authors = ["Denis Vazhenin"] - spec.email = ["denis.vazhenin@me.com"] - spec.description = %q{Faker extension providing japanese names} - spec.summary = %q{Faker extension for japanese names} - spec.license = "MIT" + spec.name = 'faker_japanese' + spec.version = Faker::Japanese::VERSION + spec.authors = ['Denis Vazhenin'] + spec.email = ['denis.vazhenin@me.com'] + spec.description = 'Faker extension providing japanese names' + spec.summary = 'Faker extension for japanese names' + spec.license = 'MIT' - spec.files = `git ls-files`.split($/) - spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } - spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = ["lib"] + spec.bindir = 'exe' + spec.files = `git ls-files -z`.split("\x0").reject do |f| + f.match(%r{^(test|spec|features)/}) + end + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ['lib'] - spec.add_runtime_dependency "faker" - spec.add_development_dependency "bundler", "~> 1.3" - spec.add_development_dependency "rake" - spec.add_development_dependency "rspec" - spec.add_development_dependency "rspec-expectations" - spec.add_development_dependency "fuubar" - spec.add_development_dependency "yard" + spec.add_development_dependency 'bundler', '~> 1.8' + spec.add_development_dependency 'rake', '~> 10.0' + spec.add_development_dependency 'rspec', '~> 3.2.0' + spec.add_development_dependency 'rspec-expectations', '~> 3.2.0' + spec.add_development_dependency 'rspec-mocks', '~> 3.2.1' + spec.add_development_dependency 'awesome_print', '~> 1.6.1' + spec.add_development_dependency 'looksee', '~> 3.1.0' + spec.add_development_dependency 'pry', '~> 0.10.1' + spec.add_development_dependency 'yard', '~> 0.8.7.6' + spec.add_development_dependency 'fuubar' + spec.add_development_dependency 'coveralls' + spec.add_development_dependency 'rubocop' + + spec.add_runtime_dependency 'faker' end diff --git a/lib/faker/japanese.rb b/lib/faker/japanese.rb new file mode 100644 index 0000000..656b939 --- /dev/null +++ b/lib/faker/japanese.rb @@ -0,0 +1 @@ +require_relative '../faker_japanese' diff --git a/lib/faker_japanese.rb b/lib/faker_japanese.rb index e81c14f..f06dd0d 100644 --- a/lib/faker_japanese.rb +++ b/lib/faker_japanese.rb @@ -1,68 +1,101 @@ require 'faker' +require 'yaml' +# Faker module Faker - module Japanese - SELFDIR = File.expand_path(File.dirname(__FILE__)) + # Japanese localization for Faker + module Japanese + # Location on the disk of this script + SELFDIR = File.expand_path(File.dirname(__FILE__)) - class Kanji < String - attr_reader :yomi, :kana, :romaji + # Kanji string + class Kanji < String + attr_reader :yomi, :kana, :romaji - def initialize(kanji, yomi, kana, romaji) - super(kanji) - @yomi = yomi - @kana = kana - @romaji = romaji - end - end + # Create new Kanji string instance + # @param [String] kanji string in kanji from + # @param [String] yomi string with hiragana readings + # @param [String] kana string with katakana readings + # @param [String] romaji romanized string + def initialize(kanji, yomi, kana, romaji) + super(kanji) + @yomi = yomi + @kana = kana + @romaji = romaji + end + end - class Base - class << self + # Faker Base class + class Base + class << self + # Using callback to store loaded data when subclass is created + # @param [Class] klass class name + def inherited(klass) + fail("#{klass} should be Class") unless klass.is_a? Class + klass.class_variable_set '@@data', load_data(klass) + end - # Using callback to store loaded data when subclass is created - def inherited(klass) - klass.class_variable_set "@@data", load_data(klass) - end + # Convert full class name to lower case string with class name only + # @param [Class] klass class name + # @return [String] + def demodulize(klass) + klass.to_s.split('::').last.downcase + end - # Load fake data from yml file - def load_data(klass) - datafile = File.join(SELFDIR, 'faker_japanese', - 'data', "#{klass.to_s.split('::').last.downcase}.yml") - if datafile && File.readable?(datafile) - data = YAML.load_file(datafile).each_with_object({}){|(k,v), h| h[k.to_sym] = v} - data.inject({}) do |res, item| - key, values, = item - res.update(key => values.map! { |v| Kanji.new(*v) }) - end - else - nil - end - end + # Load yml file with minor pre-processing + # @param [String] filepath full path to the file + # @return [Hash] + def load_raw_yaml(filepath) + return nil unless filepath && File.readable?(filepath) + YAML.load_file(filepath).each_with_object({}) do |(k, v), h| + h[k.to_sym] = v + end + end - # Search - def fetch(key) - val = self.class_variable_get("@@data")[key] - ret = val[rand(val.size)] - end + # Created dictionary with loaded data + # @param [Module] klass class name + def load_data(klass) + datafile = File.join(SELFDIR, + 'faker_japanese', + 'data', "#{demodulize(klass)}.yml") + data = load_raw_yaml(datafile) + return data if data.nil? + data.inject({}) do |res, item| + key, values = item + res.update(key => values.map! { |v| Kanji.new(*v) }) + end + data + end - # Swap method if block was evaluated to true - def swap_method(klass, name) - original_method =klass.method(name) - new_method =method(name) - klass.singleton_class.send :define_method, name, proc { - yield ? new_method.call : original_method.call - } - end + # Fetch random value from name dictionary + # @param [String] key in the @@data + # @return [Kanji] + def fetch(key) + val = class_variable_get('@@data')[key] + val[rand(val.size)] + end - # Decide which method to use based on value of Faker::Config.locale - def use_japanese_method(klass, name) - swap_method(klass, name) do - Faker::Config.locale == "ja" - end - end + # Swap method if block was evaluated to true + # @param [Class] klass name of the class + # @param [Symbol] name method name + def swap_method(klass, name) + original_method = klass.method(name) + new_method = method(name) + proc = proc { yield ? new_method.call : original_method.call } + klass.singleton_class.send(:define_method, name, proc) + end - end # << self - end # Base - end # Japanese + # Decide which method to use based on value of Faker::Config.locale + # @param [Class] klass name of the class + # @param [Symbol] name method name + def use_japanese_method(klass, name) + swap_method(klass, name) do + Faker::Config.locale == :ja + end + end + end # << self + end # Base + end # Japanese end # Faker require 'faker_japanese/version' diff --git a/lib/faker_japanese/name.rb b/lib/faker_japanese/name.rb index 61ad729..62969ed 100644 --- a/lib/faker_japanese/name.rb +++ b/lib/faker_japanese/name.rb @@ -1,26 +1,30 @@ module Faker + # Japanese localization for Faker module Japanese + # Name localization class Name < Base class << self - - # Return fake first name + # Fake first name + # @return [Kanji] def first_name fetch(:first_name) end - # Return fake last name + # Fake last name + # @return [Kanji] def last_name fetch(:last_name) end - # Return fake name, which is a string combining last and first name + # Fake full name + # @return [Kanji] string combining last and first name def name - first_name =fetch(:first_name) - last_name =fetch(:last_name) - name_kanji ="#{last_name} #{first_name}" - name_yomi ="#{last_name.yomi} #{first_name.yomi}" - name_kana ="#{last_name.kana} #{first_name.kana}" - name_romaji ="#{last_name.romaji} #{first_name.romaji}" + first_name = fetch(:first_name) + last_name = fetch(:last_name) + name_kanji = "#{last_name} #{first_name}" + name_yomi = "#{last_name.yomi} #{first_name.yomi}" + name_kana = "#{last_name.kana} #{first_name.kana}" + name_romaji = "#{last_name.romaji} #{first_name.romaji}" Kanji.new(name_kanji, name_yomi, name_kana, name_romaji) end end diff --git a/lib/faker_japanese/version.rb b/lib/faker_japanese/version.rb index a946c4b..32b3bce 100644 --- a/lib/faker_japanese/version.rb +++ b/lib/faker_japanese/version.rb @@ -1,5 +1,7 @@ module Faker - module Japanese - VERSION = "0.2.0" - end + # Japanese localization for Faker + module Japanese + # Current version + VERSION = '0.2.1' + end end diff --git a/spec/lib/faker_japanese_spec.rb b/spec/lib/faker_japanese_spec.rb index 7a55bf3..5b4576b 100644 --- a/spec/lib/faker_japanese_spec.rb +++ b/spec/lib/faker_japanese_spec.rb @@ -1,48 +1,91 @@ require 'spec_helper' describe Faker::Japanese do + context 'when locale is NOT set to :ja' do - it "should use native methods when locale is not set to ja" do - if (Faker::Config.locale != 'ja') - name = Faker::Name.name - name.should_not be_nil - name.contains_cjk?.should == false - first_name = Faker::Name.first_name - first_name.should_not be_nil - first_name.contains_cjk?.should == false - last_name = Faker::Name.first_name - last_name.should_not be_nil - last_name.contains_cjk?.should == false - else - fail + before(:all) { + Faker::Config.locale = :en + } + + after(:all) { + Faker::Config.locale = :en + } + + it 'uses default locale' do + expect(Faker::Config.locale).to eq(:en) + expect(Faker::Config.locale).not_to eq(:ja) end - end - it "should not use japanese method when locale is not set to ja" do - name = Faker::Name.name - expect { name.yomi }.to raise_error NoMethodError - expect { name.kana }.to raise_error NoMethodError - expect { name.romaji }.to raise_error NoMethodError - end + describe Faker::Name, 'use original methods' do + it '#name' do + name = Faker::Name.name + expect(name).not_to be_nil + expect(name.ascii_only?).to be_truthy + expect(name.contains_cjk?).to be_falsey + expect { name.yomi }.to raise_error NoMethodError + expect { name.kana }.to raise_error NoMethodError + expect { name.romaji }.to raise_error NoMethodError + end - it "should use japanese method when locale is set to ja" do - Faker::Config.locale = 'ja' - if (Faker::Config.locale == 'ja') - first_name = Faker::Name.first_name - first_name.should_not be_nil - first_name.contains_cjk?.should == true - last_name = Faker::Name.last_name - last_name.should_not be_nil - last_name.contains_cjk?.should == true - name = Faker::Name.name - name.should_not be_nil - name.contains_cjk?.should == true - name.yomi.contains_cjk?.should == true - name.kana.contains_cjk?.should == true - name.romaji.contains_cjk?.should == false - else - fail + it '#first_name' do + first_name = Faker::Name.first_name + expect(first_name).not_to be_nil + expect(first_name.ascii_only?).to be_truthy + expect(first_name.contains_cjk?).to be_falsey + end + + it '#last_name' do + last_name = Faker::Name.last_name + expect(last_name).not_to be_nil + expect(last_name.ascii_only?).to be_truthy + expect(last_name.contains_cjk?).to be_falsey + end end end + context 'when locale is set to ja' do + + before(:all) { + Faker::Config.locale = :ja + } + + after(:all) { + Faker::Config.locale = :en + } + + it 'uses japanese locale :ja' do + expect(Faker::Config.locale).to eq(:ja) + expect(Faker::Config.locale).to_not eq(:en) + end + + describe Faker::Name, 'use japanese specific methods' do + it '#name' do + name = Faker::Name.name + expect(name).not_to be_nil + expect(name.ascii_only?).to be_falsey + expect(name.contains_cjk?).to be_truthy + [:yomi, :kana, :romaji].each do |method| + expect(name.respond_to?(method)).to be_truthy + end + expect(name.yomi.contains_cjk?).to be_truthy + expect(name.kana.contains_cjk?).to be_truthy + expect(name.romaji.contains_cjk?).to be_falsey + end + + it '#first_name' do + first_name = Faker::Name.first_name + expect(first_name).not_to be_nil + expect(first_name.ascii_only?).to be_falsey + expect(first_name.contains_cjk?).to be_truthy + end + + it '#last_name' do + last_name = Faker::Name.last_name + expect(last_name).not_to be_nil + expect(last_name.ascii_only?).to be_falsey + expect(last_name.contains_cjk?).to be_truthy + end + + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 528680f..34cfeac 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,22 @@ +# Coverage and Coveralls +require 'simplecov' +require 'coveralls' + +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ + Coveralls::SimpleCov::Formatter, + SimpleCov::Formatter::HTMLFormatter +] +SimpleCov.start do + # disable coverage tracking + add_filter 'spec' # rspec tests +end + +# Use Coveralls formatter only in CI environment +if ENV['CI'].eql?('true') || ENV['TRAVIS'].eql?('true') || ENV['COVERALLS_REPO_TOKEN'] + Coveralls.wear! +end + +$LOAD_PATH.unshift File.expand_path('../lib', __FILE__) require 'faker_japanese' class String @@ -10,6 +29,13 @@ def contains_cjk? I18n.enforce_available_locales = true RSpec.configure do |config| + config.color = true config.failure_color = :magenta config.tty = true + config.expect_with :rspec do |c| + c.syntax = :expect + end end + +# For debugging +require 'pry'