├── lib ├── langue-japanese.rb └── langue │ ├── japanese.rb │ └── japanese │ ├── version.rb │ ├── words │ ├── pronoun.rb │ ├── conjunction.rb │ ├── interjection.rb │ ├── adverb.rb │ ├── determiner.rb │ ├── particle.rb │ ├── prefix.rb │ ├── morpheme_filter.rb │ ├── period.rb │ ├── adjectival_noun.rb │ ├── noun.rb │ ├── adjective.rb │ ├── verb.rb │ ├── attribute.rb │ └── classifier.rb │ ├── logging.rb │ ├── language.rb │ ├── inflector.rb │ ├── structurer.rb │ ├── inflector │ ├── inflection.rb │ ├── inflections.rb │ └── default.rb │ ├── shaper.rb │ └── parser.rb ├── Rakefile ├── spec ├── langue │ ├── japanese_spec.rb │ └── japanese │ │ ├── words │ │ ├── adverb_spec.rb │ │ ├── particle_spec.rb │ │ ├── conjunction_spec.rb │ │ ├── determiner_spec.rb │ │ ├── interjection_spec.rb │ │ ├── pronoun_spec.rb │ │ ├── period_spec.rb │ │ ├── adjectival_noun_spec.rb │ │ ├── noun_spec.rb │ │ ├── adjective_spec.rb │ │ └── verb_spec.rb │ │ ├── shaper_spec.rb │ │ ├── inflector │ │ ├── inflections_spec.rb │ │ └── inflection_spec.rb │ │ ├── structurer_spec.rb │ │ ├── data.yaml │ │ ├── language_spec.rb │ │ ├── parser_spec.rb │ │ └── inflector_spec.rb └── spec_helper.rb ├── .gitignore ├── Gemfile ├── langue-japanese.gemspec ├── LICENSE └── README.md /lib/langue-japanese.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese' 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | require "bundler/gem_tasks" 3 | -------------------------------------------------------------------------------- /lib/langue/japanese.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese/version' 2 | require 'langue/japanese/language' 3 | -------------------------------------------------------------------------------- /lib/langue/japanese/version.rb: -------------------------------------------------------------------------------- 1 | module Langue 2 | module Japanese 3 | VERSION = '0.0.4' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/langue/japanese_spec.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese' 2 | 3 | describe Langue::Japanese do 4 | it 'has VERSION constant' do 5 | described_class.should be_const_defined(:VERSION) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | source 'http://atedesign:jth52EsWLu7a@gems.atedesign.co.jp' 3 | 4 | # Specify your gem's dependencies in langue-japanese.gemspec 5 | gemspec 6 | 7 | gem 'mecab-ruby', :git => 'git://github.com/takkkun/mecab-ruby.git' 8 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/pronoun.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/classifier' 3 | 4 | module Langue 5 | module Japanese 6 | class Pronoun < ::Langue::Pronoun 7 | extend Classifier 8 | 9 | def self.take(morphemes, index) 10 | pronoun?(morphemes, index) ? 1 : 0 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/conjunction.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/classifier' 3 | 4 | module Langue 5 | module Japanese 6 | class Conjunction < ::Langue::Conjunction 7 | extend Classifier 8 | 9 | def self.take(morphemes, index) 10 | if conjunction?(morphemes, index) 11 | 1 12 | else 13 | 0 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/interjection.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/classifier' 3 | 4 | module Langue 5 | module Japanese 6 | class Interjection < ::Langue::Interjection 7 | extend Classifier 8 | 9 | def self.take(morphemes, index) 10 | if interjection?(morphemes, index) 11 | 1 12 | else 13 | 0 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/langue/japanese/logging.rb: -------------------------------------------------------------------------------- 1 | module Langue 2 | module Japanese 3 | module Logging 4 | def null_logger 5 | return NullLogger.new unless Object.const_defined?(:Fluent) 6 | return NullLogger.new unless Fluent.const_defined?(:Logger) 7 | Fluent::Logger::NullLogger.open 8 | end 9 | 10 | class NullLogger 11 | def post(tag, map) 12 | post_with_time(tag, map, nil) 13 | end 14 | 15 | def post_with_time(tag, map, time) 16 | false 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/adverb.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/classifier' 3 | 4 | module Langue 5 | module Japanese 6 | class Adverb < ::Langue::Adverb 7 | extend Classifier 8 | 9 | def self.take(morphemes, index) 10 | if adverb?(morphemes, index) 11 | take_adverb(morphemes, index) 12 | else 13 | 0 14 | end 15 | end 16 | 17 | def self.take_adverb(morphemes, index) 18 | size = 0 19 | size += 1 while adverb?(morphemes, index + size) 20 | size 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/determiner.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/classifier' 3 | 4 | module Langue 5 | module Japanese 6 | class Determiner < ::Langue::Determiner 7 | extend Classifier 8 | 9 | def self.take(morphemes, index) 10 | if determiner?(morphemes, index) 11 | take_determiner(morphemes, index) 12 | else 13 | 0 14 | end 15 | end 16 | 17 | def self.take_determiner(morphemes, index) 18 | size = 0 19 | size += 1 while determiner?(morphemes, index + size) 20 | size 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/adverb_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/adverb' 4 | 5 | describe Langue::Japanese::Adverb do 6 | it 'inherits Langue::Adverb' do 7 | described_class.superclass.should == Langue::Adverb 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Adverb, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a adverb' do 20 | @pairs = { 21 | 'とても話す' => 1, 22 | 'とてもとても話す' => 2 23 | } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/particle.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/classifier' 3 | 4 | module Langue 5 | module Japanese 6 | class Particle < ::Langue::Particle 7 | extend Classifier 8 | 9 | def self.take(morphemes, index) 10 | if particle?(morphemes, index) 11 | take_particle(morphemes, index) 12 | else 13 | 0 14 | end 15 | end 16 | 17 | def self.take_particle(morphemes, index) 18 | size = 0 19 | size += 1 while particle?(morphemes, index + size) && !conjunctive_particle?(morphemes, index + size) 20 | size 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/particle_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/particle' 4 | 5 | describe Langue::Japanese::Particle do 6 | it 'inherits Langue::Particle' do 7 | described_class.superclass.should == Langue::Particle 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Particle, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a particle' do 20 | @pairs = { 21 | 'は' => 1, 22 | 'とは' => 2, 23 | 'て' => 0 24 | } 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/conjunction_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/conjunction' 4 | 5 | describe Langue::Japanese::Conjunction do 6 | it 'inherits Langue::Conjunction' do 7 | described_class.superclass.should == Langue::Conjunction 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Conjunction, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a conjunction' do 20 | @pairs = { 21 | 'だから' => 1, 22 | 'だからそして' => 1 23 | } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/determiner_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/determiner' 4 | 5 | describe Langue::Japanese::Determiner do 6 | it 'inherits Langue::Determiner' do 7 | described_class.superclass.should == Langue::Determiner 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Determiner, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a determiner' do 20 | @pairs = { 21 | 'おおきな太陽' => 1, 22 | 'おおきなおおきな太陽' => 2 23 | } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/interjection_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/interjection' 4 | 5 | describe Langue::Japanese::Interjection do 6 | it 'inherits Langue::Interjection' do 7 | described_class.superclass.should == Langue::Interjection 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Interjection, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a interjection' do 20 | @pairs = { 21 | 'おはよう' => 1, 22 | 'おはようごきげんよう' => 1 23 | } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/prefix.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese/words/morpheme_filter' 2 | 3 | module Langue 4 | module Japanese 5 | module Prefix 6 | def self.included(object) 7 | object.class_eval { include MorphemeFilter } 8 | object.filter { |word, morphemes| morphemes[word.prefix_morphemes.size..-1] } 9 | end 10 | 11 | def prefix_morphemes 12 | @prefix_morphemes ||= extract_prefix_morphemes 13 | end 14 | 15 | def prefix 16 | @prefix = create_prefix unless instance_variable_defined?(:@prefix) 17 | @prefix 18 | end 19 | 20 | private 21 | 22 | def create_prefix 23 | prefix_morphemes.map(&:text).join 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/pronoun_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/pronoun' 4 | 5 | describe Langue::Japanese::Pronoun do 6 | it 'inherits Langue::Pronoun' do 7 | described_class.superclass.should == Langue::Pronoun 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Pronoun, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a pronoun' do 20 | @pairs = { 21 | 'それだ' => 1, 22 | '僕だ' => 1, 23 | 'それ僕だ' => 1, 24 | '会話それだ' => 0, 25 | 'かっこいいこと' => 0, 26 | '会話だ' => 0, 27 | '話すこと' => 0 28 | } 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /langue-japanese.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/langue/japanese/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.authors = ["Takahiro Kondo"] 6 | gem.email = ["kondo@atedesign.net"] 7 | gem.description = %q{It provides the operations to Japanese.} 8 | gem.summary = %q{The foundation for Japanese} 9 | gem.homepage = "" 10 | 11 | gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 12 | gem.files = `git ls-files`.split("\n") 13 | gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 14 | gem.name = "langue-japanese" 15 | gem.require_paths = ["lib"] 16 | gem.version = Langue::Japanese::VERSION 17 | 18 | gem.add_runtime_dependency 'langue' 19 | gem.add_runtime_dependency 'activesupport' 20 | 21 | gem.add_development_dependency 'rspec' 22 | end 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Takahiro Kondo 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /lib/langue/japanese/language.rb: -------------------------------------------------------------------------------- 1 | require 'langue' 2 | 3 | module Langue 4 | module Japanese 5 | class Language < Langue::Language 6 | def parser 7 | @parser ||= Parser.new(@options) 8 | end 9 | depend_to :parser, 'langue/japanese/parser' 10 | 11 | def shaper 12 | @shaper ||= Shaper.new(@options) 13 | end 14 | depend_to :shaper, 'langue/japanese/shaper' 15 | 16 | def structurer 17 | @structurer ||= Structurer.new(@options) 18 | end 19 | depend_to :structurer, 'langue/japanese/structurer' 20 | 21 | def inflector 22 | @inflector ||= Inflector.new(@options) 23 | end 24 | depend_to :inflector, 'langue/japanese/inflector' 25 | 26 | def parse(text) 27 | parser.parse(text) 28 | end 29 | 30 | def shape_person_name(morphemes, person_name) 31 | shaper.shape_person_name(morphemes, person_name) 32 | end 33 | 34 | def structure(morphemes) 35 | structurer.structure(morphemes) 36 | end 37 | 38 | def inflect(classification, word, form, options = {}) 39 | inflector.inflect(classification, word, form, options) 40 | end 41 | end 42 | end 43 | 44 | support(Japanese::Language) 45 | end 46 | -------------------------------------------------------------------------------- /spec/langue/japanese/shaper_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/shaper' 4 | 5 | describe Langue::Japanese::Shaper, '#initialize' do 6 | it 'sets an instance of Langue::Japanese::Logging::NullLogger to @logger' do 7 | parser = described_class.new 8 | logger = parser.instance_eval { @logger } 9 | logger.should be_a(Langue::Japanese::Logging::NullLogger) 10 | end 11 | 12 | context 'with logger option' do 13 | it 'sets the value of logger option to @logger' do 14 | parser = described_class.new(:logger => 'logger') 15 | logger = parser.instance_eval { @logger } 16 | logger.should == 'logger' 17 | end 18 | end 19 | end 20 | 21 | describe Langue::Japanese::Shaper, '#shape_person_name' do 22 | it 'shapes the morphemes as person name' do 23 | shaper = described_class.new 24 | 25 | { 26 | 'あたしの名前は天道あかねよ' => ['天道あかね', 6], 27 | 'オレの名前は早乙女乱馬だ' => ['早乙女乱馬', 6] 28 | }.each do |text, params| 29 | name, size = params 30 | morphemes = parser.parse(text) 31 | shaped_morphemes = shaper.shape_person_name(morphemes, name) 32 | shaped_morphemes.should have(size).items 33 | morpheme = shaped_morphemes.find { |m| m.classified?(*%w(名詞 固有名詞 人名)) } 34 | morpheme.text.should == name 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/morpheme_filter.rb: -------------------------------------------------------------------------------- 1 | module Langue 2 | module Japanese 3 | module MorphemeFilter 4 | def self.included(object) 5 | object.extend(ClassMethods) 6 | end 7 | 8 | def body_morphemes 9 | @body_morphemes ||= self.class.apply_filters(self) 10 | end 11 | 12 | def body 13 | @body = create_body unless instance_variable_defined?(:@body) 14 | @body 15 | end 16 | 17 | private 18 | 19 | def create_body 20 | return nil if body_morphemes.empty? 21 | 22 | morphemes = body_morphemes[0..-2].map(&:text) 23 | 24 | if inflection 25 | morphemes << body_morphemes[-1].root_form 26 | else 27 | morphemes << body_morphemes[-1].text 28 | end 29 | 30 | morphemes.join 31 | end 32 | 33 | module ClassMethods 34 | def filters 35 | @filters ||= [] 36 | end 37 | 38 | def filter(&filter) 39 | remove_instance_variable(:@body_morphemes) if instance_variable_defined?(:@body_morphemes) 40 | filters << filter 41 | end 42 | 43 | def apply_filters(original_morphemes) 44 | filters.inject(original_morphemes) { |morphemes, filter| filter[original_morphemes, morphemes] } 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is langue-japanese 2 | ======================= 3 | 4 | It provides the operations to Japanese. 5 | 6 | Installation 7 | ------------ 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | gem 'langue' 12 | gem 'langue-japanese' 13 | 14 | # When doing morphological analysis 15 | gem 'mecab-ruby', :git => 'path to mecab-ruby repository' 16 | 17 | And then execute: 18 | 19 | $ bundle 20 | 21 | Or install it yourself as: 22 | 23 | $ gem install langue 24 | $ gem install langue-japanese 25 | 26 | langue-japanese gem runs on langue gem. So it depends to langue gem. 27 | 28 | It also uses MeCab with morphological analysis, this gem depends too to 29 | mecab-ruby gem if you do it. 30 | 31 | Usage 32 | ----- 33 | 34 | # coding: utf-8 35 | require 'langue-japanese' 36 | 37 | # Get a language class 38 | language = Langue['japanese'].new 39 | 40 | # Split to morphemes a text 41 | morphemes = language.parse('今日は妹と一緒にお買い物してきたよ。楽しかった〜') 42 | 43 | # Create a structured text from the morphemes 44 | text = language.structure(morphemes) 45 | 46 | Contributing 47 | ------------ 48 | 49 | 1. Fork it 50 | 2. Create your feature branch (`git checkout -b my-new-feature`) 51 | 3. Commit your changes (`git commit -am 'Added some feature'`) 52 | 4. Push to the branch (`git push origin my-new-feature`) 53 | 5. Create new Pull Request 54 | -------------------------------------------------------------------------------- /lib/langue/japanese/inflector.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese/inflector/inflections' 2 | require 'langue/japanese/logging' 3 | 4 | module Langue 5 | module Japanese 6 | class Inflector 7 | include Logging 8 | 9 | # Get the inflections. 10 | # 11 | # If given a block, define the inflections. 12 | # 13 | # @yield [] define the inflections 14 | def self.inflections(&define) 15 | (@inflections ||= Inflections.new).tap do |inflections| 16 | inflections.instance_eval(&define) if block_given? 17 | end 18 | end 19 | 20 | # @param [Hash] options 21 | # @option options [Logger] :logger 22 | def initialize(options = {}) 23 | @logger = options[:logger] || null_logger 24 | end 25 | 26 | # Inflect the word. 27 | # 28 | # @param [String] classification the inflectional classification 29 | # @param [String] word root form of the word to inflect 30 | # @param [String] form the inflectional form 31 | # @param [Hash] options 32 | # @option options [String] :following 33 | # @option options [Boolean] :desu 34 | # @return [String] the inflected word 35 | def inflect(classification, word, form, options = {}) 36 | inflection = self.class.inflections[classification] 37 | raise ArgumentError, %("#{classification}" inflection does not exist) unless inflection 38 | inflection.inflect(word, form, options) 39 | end 40 | end 41 | end 42 | end 43 | 44 | require 'langue/japanese/inflector/default' 45 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/period.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'langue/word' 3 | require 'langue/japanese/words/classifier' 4 | 5 | module Langue 6 | module Japanese 7 | class Period < ::Langue::Period 8 | COMMAS = %w(, , 、) 9 | DOTS = COMMAS + %w(. . 。 ・ ‥ …) 10 | MARKS = %w(! ! ? ?) 11 | 12 | extend Classifier 13 | 14 | def self.take(morphemes, index) 15 | if dot?(morphemes, index) 16 | take_dot(morphemes, index) 17 | elsif mark?(morphemes, index) 18 | take_mark(morphemes, index) 19 | else 20 | 0 21 | end 22 | end 23 | 24 | def self.dot?(morphemes, index) 25 | morphemes.at(index) { |m| DOTS.include?(m.text) } 26 | end 27 | 28 | def self.mark?(morphemes, index) 29 | morphemes.at(index) { |m| MARKS.include?(m.text) } 30 | end 31 | 32 | def self.take_dot(morphemes, index) 33 | size = 0 34 | size += 1 while dot?(morphemes, index + size) 35 | size == 1 && COMMAS.include?(morphemes[index].text) ? 0 : size 36 | end 37 | 38 | def self.take_mark(morphemes, index) 39 | size = 0 40 | size += 1 while mark?(morphemes, index + size) 41 | size 42 | end 43 | 44 | def exclamation? 45 | @exclamation = !!(text =~ /[!!]/) unless instance_variable_defined?(:@exclamation) 46 | @exclamation 47 | end 48 | 49 | def question? 50 | @question = !!(text =~ /[??]/) unless instance_variable_defined?(:@question) 51 | @question 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/langue/japanese/structurer.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/core_ext/string/inflections' 2 | 3 | require 'langue/text' 4 | require 'langue/sentence' 5 | require 'langue/word' 6 | require 'langue/japanese/logging' 7 | 8 | module Langue 9 | module Japanese 10 | class Structurer 11 | include Logging 12 | 13 | WORD_CLASSES = %w( 14 | period 15 | interjection 16 | determiner 17 | conjunction 18 | particle 19 | adverb 20 | verb 21 | adjective 22 | adjectival_noun 23 | pronoun 24 | noun 25 | ).map do |word_name| 26 | require "langue/japanese/words/#{word_name}" 27 | Langue::Japanese.const_get(word_name.camelize) 28 | end 29 | 30 | def initialize(options = {}) 31 | @logger = options[:logger] || null_logger 32 | end 33 | 34 | def structure(morphemes) 35 | sentences = [] 36 | words = [] 37 | arrived = false 38 | index = 0 39 | length = morphemes.length 40 | 41 | while index < length 42 | word_class = nil 43 | size = 0 44 | 45 | WORD_CLASSES.each do |wc| 46 | s = wc.take(morphemes, index) 47 | 48 | if s > 0 49 | word_class = wc 50 | size = s 51 | break 52 | end 53 | end 54 | 55 | if word_class.nil? 56 | word_class = Word 57 | size = 1 58 | end 59 | 60 | word = word_class.new(morphemes[index, size]) 61 | 62 | if arrived && !word.instance_of?(Period) 63 | sentences << Sentence.new(words) 64 | words.clear 65 | arrived = false 66 | elsif word.instance_of?(Period) 67 | arrived = true 68 | end 69 | 70 | words << word 71 | index += size 72 | end 73 | 74 | sentences << Sentence.new(words) unless words.empty? 75 | Text.new(sentences) 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/langue/japanese/inflector/inflection.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | module Langue 3 | module Japanese 4 | class Inflector 5 | class Inflection 6 | NIGORU = { 7 | 'た' => 'だ', 8 | 'ち' => 'じ', 9 | 'て' => 'で', 10 | 'と' => 'ど' 11 | } 12 | 13 | SUMU = NIGORU.invert.merge('ぢ' => 'ち') 14 | 15 | # @param [String] base_suffix the base suffix 16 | # @param [Hash] suffixes suffix for each the 17 | # inflectional form 18 | def initialize(base_suffix, suffixes) 19 | @base_suffix = base_suffix 20 | @suffixes = suffixes 21 | end 22 | 23 | # Inflect the word. 24 | # 25 | # @param [String] word root form of the word to inflect 26 | # @param [String] form the inflectional form 27 | # @param [Hash] options 28 | # @option options [String] :following 29 | # @option options [Boolean] :desu 30 | # @return [String] the inflected word 31 | def inflect(word, form, options = {}) 32 | raise ArgumentError, %(the word does not end with "#{@base_suffix}") unless word.end_with?(@base_suffix) 33 | stem = word.chomp(@base_suffix) 34 | 35 | suffix = @suffixes[form] 36 | raise ArgumentError, %("#{form}" inflectional form does not defined in the inflection) unless suffix 37 | suffix = suffix[options] if suffix.is_a?(Proc) 38 | 39 | following = options[:following] || '' 40 | 41 | if %w(連用タ接続 連用テ接続).include?(form) 42 | nigoru = false 43 | suffix, nigoru = suffix if suffix.is_a?(Array) 44 | following = affect(following, nigoru ? NIGORU : SUMU) 45 | end 46 | 47 | stem + suffix + following 48 | end 49 | 50 | private 51 | 52 | def affect(text, map) 53 | prefix = map.keys.find { |p| text.start_with?(p) } 54 | prefix ? text.sub(/^#{prefix}/, map[prefix]) : text 55 | end 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/langue/japanese/inflector/inflections.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese/inflector/inflection' 2 | 3 | module Langue 4 | module Japanese 5 | class Inflector 6 | class Inflections < Hash 7 | 8 | # Define the inflection. 9 | # 10 | # @param [String] classification the inflectional classification 11 | # @param [String] base_suffix the base suffix 12 | # @param [Hash] suffixes suffix for each the 13 | # inflectional form 14 | def inflection(classification, base_suffix, suffixes = {}) 15 | if categorizing? 16 | parts = [] 17 | inadequate = @required_forms - suffixes.keys 18 | parts << "#{enumerate_forms(inadequate)} has not been defined" unless inadequate.empty? 19 | excess = suffixes.keys - @required_forms 20 | parts << "#{enumerate_forms(excess)} should not be defined" unless excess.empty? 21 | raise ArgumentError, "#{parts.join(', and ')}" unless parts.empty? 22 | end 23 | 24 | self[classification] = Inflection.new(base_suffix, suffixes) 25 | end 26 | 27 | # Make the category for inflections. 28 | # 29 | # @param [Array] required_forms inflectional forms that 30 | # inflections in the category need 31 | # @yield [] define inflections 32 | def category(*required_forms, &define) 33 | @required_forms = required_forms 34 | instance_eval(&define) if block_given? 35 | ensure 36 | remove_instance_variable(:@required_forms) 37 | end 38 | 39 | # Determine if you are defining inflections with a category. 40 | # 41 | # @return whether if you are defining inflections with a category 42 | def categorizing? 43 | instance_variable_defined?(:@required_forms) 44 | end 45 | 46 | private 47 | 48 | def enumerate_forms(forms) 49 | last = forms.last 50 | other = forms[0..-2].join(', ') 51 | other.empty? ? last : "#{other} and #{last}" 52 | end 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/period_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/period' 4 | 5 | describe Langue::Japanese::Period do 6 | it 'inherits Langue::Period' do 7 | described_class.superclass.should == Langue::Period 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Period, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a period' do 20 | @pairs = { 21 | '。さて' => 1, 22 | '…… さて' => 2, 23 | '‥・ さて' => 2, 24 | '、、、 さて' => 3, 25 | '。。。 さて' => 3, 26 | '. さて' => 1, 27 | '... さて' => 3, 28 | '.さて' => 1, 29 | '..さて' => 2, 30 | '.。.さて' => 3, 31 | '、。さて' => 2, 32 | '! さて' => 1, 33 | '! さて' => 1, 34 | '!! さて' => 2, 35 | '!! さて' => 2, 36 | '!! さて' => 2, 37 | '? さて' => 1, 38 | '? さて' => 1, 39 | '?? さて' => 2, 40 | '?? さて' => 2, 41 | '!? さて' => 2, 42 | '!? さて' => 2, 43 | '!?! さて' => 3, 44 | '!?!? さて' => 4, 45 | '!??!!?! さて' => 7, 46 | '、さて' => 0, 47 | ',さて' => 0, 48 | ', さて' => 0 49 | } 50 | end 51 | end 52 | 53 | describe Langue::Japanese::Period, '#exclamation?' do 54 | it 'returns true if include exclamation mark' do 55 | period('!').should be_exclamation 56 | period('!').should be_exclamation 57 | period('?!').should be_exclamation 58 | end 59 | 60 | it 'returns false if do not include exclamation marks' do 61 | period('?').should_not be_exclamation 62 | end 63 | end 64 | 65 | describe Langue::Japanese::Period, '#question?' do 66 | it 'returns true if include question mark' do 67 | period('?').should be_question 68 | period('?').should be_question 69 | period('!?').should be_question 70 | end 71 | 72 | it 'returns false if do not include question marks' do 73 | period('!').should_not be_question 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/langue/japanese/shaper.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'langue/morpheme' 3 | require 'langue/morphemes' 4 | require 'langue/japanese/logging' 5 | 6 | module Langue 7 | module Japanese 8 | class Shaper 9 | include Logging 10 | 11 | def initialize(options = {}) 12 | @logger = options[:logger] || null_logger 13 | end 14 | 15 | def shape_person_name(morphemes, person_name) 16 | Morphemes.new.tap do |new_morphemes| 17 | person_name_morphemes = [] 18 | start_index = 0 19 | person_name_size = person_name.size 20 | 21 | morphemes.each do |morpheme| 22 | text = morpheme.text 23 | index = person_name.index(text, start_index) 24 | 25 | if index == start_index 26 | person_name_morphemes << morpheme 27 | start_index += text.size 28 | 29 | if start_index == person_name_size 30 | new_morphemes << join_as_person_name(person_name_morphemes) 31 | person_name_morphemes.clear 32 | start_index = 0 33 | end 34 | else 35 | new_morphemes.concat(person_name_morphemes) << morpheme 36 | person_name_morphemes.clear 37 | start_index = 0 38 | end 39 | end 40 | end 41 | end 42 | 43 | private 44 | 45 | def join_as_person_name(morphemes) 46 | text = morphemes.map(&:text).join 47 | 48 | yomi = morphemes.inject('') do |yomi, morpheme| 49 | t = morpheme.text 50 | y = morpheme.yomi 51 | yomi + (y || t != 'ー' ? (y || '') : t) 52 | end 53 | 54 | pronunciation = morphemes.inject('') do |pronunciation, morpheme| 55 | pronunciation + (morpheme.pronunciation || '') 56 | end 57 | 58 | Morpheme.new( 59 | :text => text, 60 | :part_of_speech => '名詞', 61 | :categories => %w(固有名詞 人名), 62 | :root_form => text, 63 | :yomi => yomi, 64 | :pronunciation => pronunciation 65 | ) 66 | end 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/adjectival_noun_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/adjectival_noun' 4 | 5 | describe Langue::Japanese::AdjectivalNoun do 6 | it 'inherits Langue::Adjective' do 7 | described_class.superclass.should == Langue::Adjective 8 | end 9 | end 10 | 11 | describe Langue::Japanese::AdjectivalNoun, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes an adjectival noun' do 20 | @pairs = { 21 | '大丈夫だ' => 1, 22 | '健康だ' => 1, 23 | 'かっこいいこと' => 0, 24 | '会話だ' => 0, 25 | '話すこと' => 0 26 | } 27 | end 28 | 29 | it 'takes an adjectival noun with prefix' do 30 | @pairs = { 31 | '超大丈夫だ' => 2, 32 | '反健康だ' => 2, 33 | '超それだ' => 0, 34 | '超若干だ' => 0, 35 | '超可愛いこと' => 0, 36 | '反かっこいいこと' => 0 37 | } 38 | end 39 | 40 | it 'takes an adjectival noun with suffix' do 41 | @pairs = { 42 | '病気がちだ' => 2, 43 | '犬好きだ' => 2, 44 | '犬だ' => 0, 45 | 'それがちだ' => 0, 46 | '若干がちだ' => 0 47 | } 48 | end 49 | 50 | it 'takes a successive adjectival noun' do 51 | @pairs = { 52 | '健康大丈夫だ' => 2, 53 | '健康大丈夫がちだ' => 2, 54 | '健康大丈夫ラーメンだ' => 0 55 | } 56 | end 57 | 58 | it 'takes a complex adjectival noun' do 59 | @pairs = { 60 | '超病気がちだ' => 3, 61 | '超漆黒病気がちだ' => 4, 62 | '反超健康大丈夫だ' => 4, 63 | '反超健康大丈夫がちだ' => 4, 64 | '超犬だ' => 0, 65 | '超健康大丈夫ラーメンだ' => 0, 66 | '精神的疾患だ' => 0 67 | } 68 | end 69 | end 70 | 71 | describe Langue::Japanese::AdjectivalNoun, '#prefix' do 72 | it 'returns the prefix' do 73 | adjectival_noun('反超病気がち').prefix.should == '反超' 74 | end 75 | end 76 | 77 | describe Langue::Japanese::AdjectivalNoun, '#body' do 78 | it 'returns the text without the prefix' do 79 | adjectival_noun('反超病気がち').body.should == '病気がち' 80 | end 81 | end 82 | 83 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/adjectival_noun.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/prefix' 3 | require 'langue/japanese/words/classifier' 4 | 5 | module Langue 6 | module Japanese 7 | class AdjectivalNoun < ::Langue::Adjective 8 | include Prefix 9 | 10 | def extract_prefix_morphemes 11 | size = 0 12 | size += 1 while self.class.noun_prefix?(morphemes, size) 13 | morphemes[0, size] 14 | end 15 | 16 | extend Classifier 17 | 18 | def self.take(morphemes, index) 19 | if adjective_stem_noun?(morphemes, index) 20 | take_adjective_stem_noun(morphemes, index) 21 | elsif first_noun?(morphemes, index) 22 | take_noun_with_suffix(morphemes, index) 23 | elsif noun_prefix?(morphemes, index) 24 | take_noun_with_prefix(morphemes, index) 25 | else 26 | 0 27 | end 28 | end 29 | 30 | def self.take_adjective_stem_noun(morphemes, index) 31 | size = 0 32 | size += 1 while adjective_stem_noun?(morphemes, index + size) 33 | return 0 unless size > 0 34 | 35 | if adjective_stem_suffix?(morphemes, index + size) 36 | size 37 | elsif following_noun?(morphemes, index + size) 38 | 0 39 | else 40 | size 41 | end 42 | end 43 | 44 | def self.take_noun_with_suffix(morphemes, index) 45 | return 0 unless first_noun?(morphemes, index) 46 | size = 1 47 | size += 1 while following_noun?(morphemes, index + size) && !adjective_stem_suffix?(morphemes, index + size) 48 | return 0 unless adjective_stem_suffix?(morphemes, index + size) 49 | size += 1 while adjective_stem_suffix?(morphemes, index + size) 50 | 51 | if following_noun?(morphemes, index + size) 52 | 0 53 | else 54 | size 55 | end 56 | end 57 | 58 | def self.take_noun_with_prefix(morphemes, index) 59 | size = 0 60 | size += 1 while noun_prefix?(morphemes, index + size) 61 | return 0 unless size > 0 62 | next_size = take(morphemes, index + size) 63 | next_size > 0 ? size + next_size : 0 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/noun.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'langue/word' 3 | require 'langue/japanese/words/prefix' 4 | require 'langue/japanese/words/classifier' 5 | 6 | module Langue 7 | module Japanese 8 | class Noun < ::Langue::Noun 9 | include Prefix 10 | 11 | def extract_prefix_morphemes 12 | size = 0 13 | size += 1 while self.class.noun_prefix?(morphemes, size) 14 | morphemes[0, size] 15 | end 16 | 17 | INHIBITED_FIRST_CHARS = %w(ぁ ァ ぃ ィ ぅ ゥ ぇ ェ ぉ ォ っ ッ ー) 18 | INHIBITED_LAST_CHARS = %w() 19 | 20 | extend Classifier 21 | 22 | def self.take(morphemes, index) 23 | if first_noun?(morphemes, index) 24 | take_noun(morphemes, index) 25 | elsif noun_prefix?(morphemes, index) 26 | take_noun_with_prefix(morphemes, index) 27 | elsif adverbable_noun?(morphemes, index) 28 | take_adverbable_noun(morphemes, index) 29 | else 30 | 0 31 | end 32 | end 33 | 34 | def self.take_noun(morphemes, index) 35 | return 0 unless first_noun?(morphemes, index) 36 | all = adjective_stem_noun?(morphemes, index) 37 | size = 1 38 | 39 | while following_noun?(morphemes, index + size) || following_symbol?(morphemes, index + size) 40 | all &&= adjective_stem_noun?(morphemes, index + size) 41 | size += 1 42 | end 43 | 44 | return 0 if all 45 | return 0 if noun_conjunct_to_suru?(morphemes, index + size - 1) && suru_verb?(morphemes, index + size) 46 | first_char = morphemes[index].text[0] 47 | last_char = morphemes[index + size - 1].text[-1] 48 | return 0 if INHIBITED_FIRST_CHARS.include?(first_char) 49 | return 0 if INHIBITED_LAST_CHARS.include?(last_char) 50 | size 51 | end 52 | 53 | def self.take_noun_with_prefix(morphemes, index) 54 | size = 0 55 | size += 1 while noun_prefix?(morphemes, index + size) 56 | return 0 unless size > 0 57 | next_size = take_noun(morphemes, index + size) 58 | next_size > 0 ? size + next_size : 0 59 | end 60 | 61 | def self.take_adverbable_noun(morphemes, index) 62 | size = 0 63 | size += 1 while adverbable_noun?(morphemes, index + size) 64 | size 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/noun_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/noun' 4 | 5 | describe Langue::Japanese::Noun do 6 | it 'inherits Langue::Noun' do 7 | described_class.superclass.should == Langue::Noun 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Noun, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a noun' do 20 | @pairs = { 21 | '会話だ' => 1, 22 | 'かっこいいこと' => 0, 23 | '話すこと' => 0, 24 | '大丈夫だ' => 0, 25 | '健康だ' => 0 26 | } 27 | end 28 | 29 | it 'takes a noun with prefix' do 30 | @pairs = { 31 | '超会話だ' => 2, 32 | '超反会話だ' => 3, 33 | '超大丈夫だ' => 0, 34 | '反健康だ' => 0, 35 | '超それだ' => 0, 36 | '超若干だ' => 0, 37 | '超可愛いこと' => 0, 38 | '反かっこいいこと' => 0 39 | } 40 | end 41 | 42 | it 'takes a successive noun' do 43 | @pairs = { 44 | '緊急連絡網だ' => 3, 45 | '健康大丈夫ラーメンだ' => 3, 46 | '精神的疾患だ' => 3, 47 | '緊急大丈夫だ' => 0 48 | } 49 | end 50 | 51 | it 'takes an adverbable noun' do 52 | @pairs = { 53 | '一挙だ' => 1, 54 | '一挙ラーメン永年だ' => 1, 55 | '一挙永年ラーメンだ' => 2, 56 | 'ラーメン永年だ' => 1 57 | } 58 | end 59 | 60 | it 'does not take noun conjunct to suru-verb' do 61 | @pairs = { 62 | '連絡する' => 0, 63 | '緊急連絡する' => 0, 64 | '緊急連絡網する' => 3 65 | } 66 | end 67 | 68 | it 'does not take noun if starts with special char' do 69 | @pairs = { 70 | 'ぁ犬だ' => 0, 71 | 'ァ犬だ' => 0, 72 | 'ぃ犬だ' => 0, 73 | 'ィ犬だ' => 0, 74 | 'ぅ犬だ' => 0, 75 | 'ゥ犬だ' => 0, 76 | 'ぇ犬だ' => 0, 77 | 'ェ犬だ' => 0, 78 | 'ぉ犬だ' => 0, 79 | 'ォ犬だ' => 0, 80 | 'っ犬だ' => 0, 81 | 'ッ犬だ' => 0, 82 | 'ー犬だ' => 0 83 | } 84 | end 85 | end 86 | 87 | describe Langue::Japanese::Noun, '#prefix' do 88 | it 'returns the prefix' do 89 | noun('超反会話').prefix.should == '超反' 90 | end 91 | end 92 | 93 | describe Langue::Japanese::Noun, '#body' do 94 | it 'returns the text with the prefix' do 95 | noun('超反会話').body.should == '会話' 96 | noun('超反会話♡').body.should == '会話♡' 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/adjective.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/prefix' 3 | require 'langue/japanese/words/attribute' 4 | require 'langue/japanese/words/classifier' 5 | 6 | module Langue 7 | module Japanese 8 | class InvalidWord < StandardError; end 9 | 10 | class Adjective < ::Langue::Adjective 11 | include Prefix 12 | 13 | def extract_prefix_morphemes 14 | size = 0 15 | size += 1 while self.class.adjective_prefix?(morphemes, size) 16 | morphemes[0, size] 17 | end 18 | 19 | include Attribute 20 | 21 | has :negative, :perfective 22 | 23 | extend Classifier 24 | 25 | def self.take(morphemes, index) 26 | if first_adjective?(morphemes, index) 27 | take_adjective(morphemes, index) 28 | elsif adjective_prefix?(morphemes, index) 29 | take_adjective_with_prefix(morphemes, index) 30 | else 31 | 0 32 | end 33 | end 34 | 35 | def self.take_adjective(morphemes, index) 36 | return 0 unless first_adjective?(morphemes, index) 37 | size = 1 38 | size += 1 while following_adjective?(morphemes, index + size) || conjunctive_particle?(morphemes, index + size) && following_adjective?(morphemes, index + size + 1) 39 | size += 1 while auxiliary_verb?(morphemes, index + size) 40 | size 41 | end 42 | 43 | def self.take_adjective_with_prefix(morphemes, index) 44 | size = 0 45 | size += 1 while adjective_prefix?(morphemes, index + size) 46 | return 0 unless size > 0 47 | next_size = take_adjective(morphemes, index + size) 48 | next_size > 0 ? size + next_size : 0 49 | end 50 | 51 | def key_morpheme 52 | unless instance_variable_defined?(:@key_morpheme) 53 | @key_morpheme = if empty? 54 | nil 55 | else 56 | index = size - 1 57 | 58 | while !self.class.body_adjective?(morphemes, index) 59 | index -= 1 60 | raise InvalidWord, %("#{text}" is invalid a word as an adjective) unless self[index] 61 | end 62 | 63 | self[index] 64 | end 65 | end 66 | 67 | @key_morpheme 68 | end 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/langue/japanese/parser.rb: -------------------------------------------------------------------------------- 1 | require 'MeCab' 2 | 3 | require 'langue/morpheme' 4 | require 'langue/morphemes' 5 | require 'langue/japanese/logging' 6 | 7 | module Langue 8 | module Japanese 9 | class Parser 10 | include Logging 11 | 12 | def self.use_model? 13 | MeCab::VERSION.to_f >= 0.99 14 | end 15 | 16 | @@models = {} if use_model? 17 | 18 | def initialize(options = {}) 19 | @tagger_options = options[:tagger_options] || {} 20 | @logger = options[:logger] || null_logger 21 | @taggers = {} 22 | end 23 | 24 | attr_accessor :tagger_options 25 | 26 | def parse(text) 27 | morphemes = Morphemes.new 28 | node = tagger.parseToNode(text) 29 | 30 | while node 31 | surface = node.surface.force_encoding('utf-8') 32 | 33 | unless surface.empty? 34 | feature = node.feature.force_encoding('utf-8') 35 | morphemes << create_morpheme(surface, feature) 36 | end 37 | 38 | node = node.next 39 | end 40 | 41 | morphemes 42 | end 43 | 44 | private 45 | 46 | def tagger 47 | @taggers[Thread.current] ||= begin 48 | method_name = self.class.use_model? ? :tagger_by_model_with : :tagger_with 49 | __send__(method_name, tagger_options_as_string) 50 | end 51 | end 52 | 53 | def tagger_with(options) 54 | MeCab::Tagger.new(options) 55 | end 56 | 57 | def tagger_by_model_with(options) 58 | (@@models[options] ||= MeCab::Model.create(options)).createTagger 59 | end 60 | 61 | def tagger_options_as_string 62 | tagger_options = @tagger_options.inject([]) do |o, pair| 63 | key = pair[0].to_sym 64 | value = pair[1] 65 | 66 | case key 67 | when :sysdic 68 | o << '-d' << value 69 | when :userdic 70 | o << '-u' << value 71 | else 72 | map = { 73 | :level => 'warn', 74 | :message => "'#{key}' option is unsupported", 75 | :key => key 76 | } 77 | 78 | @logger.post('langue.japanese.parser', map) 79 | o 80 | end 81 | end 82 | 83 | tagger_options * ' ' 84 | end 85 | 86 | def create_morpheme(surface, feature) 87 | values = feature.split(',').map { |v| v == '*' ? nil : v } 88 | values[1..3] = [values[1..3].take_while {|value| !value.nil?}] 89 | values.unshift(surface) 90 | Morpheme.new(Hash[Morpheme::KEYS.zip(values)]) 91 | end 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | def operator_stub(file_name, class_name) 2 | stub.tap do |s| 3 | require "langue/japanese/#{file_name}" unless Langue::Japanese.const_defined?(class_name) 4 | Langue::Japanese.const_get(class_name).stub!(:new).and_return(s) 5 | yield s 6 | end 7 | end 8 | 9 | def parser_stub 10 | operator_stub('parser', :Parser) do |s| 11 | s.stub!(:parse).and_return('value returning from parse method') 12 | yield s if block_given? 13 | end 14 | end 15 | 16 | def shaper_stub 17 | operator_stub('shaper', :Shaper) do |s| 18 | s.stub!(:shape_person_name).and_return('value returning from shape_person_name method') 19 | yield s if block_given? 20 | end 21 | end 22 | 23 | def structurer_stub 24 | operator_stub('structurer', :Structurer) do |s| 25 | s.stub!(:structure).and_return('value returning from structure method') 26 | yield s if block_given? 27 | end 28 | end 29 | 30 | def inflector_stub 31 | operator_stub('inflector', :Inflector) do |s| 32 | s.stub!(:inflect).and_return('value returning from #inflect') 33 | yield s if block_given? 34 | end 35 | end 36 | 37 | def parser_tagger_stub(nodes = nil) 38 | stub.tap do |s| 39 | MeCab::Tagger.stub!(:new).and_return(s) 40 | 41 | if nodes 42 | node = make_node('') 43 | nodes.times { |i| node = make_node(nodes - i, node) } 44 | s.stub!(:parseToNode).and_return(make_node('', node)) 45 | end 46 | 47 | yield s if block_given? 48 | end 49 | end 50 | 51 | def parser_model_stub(parser_tagger = nil) 52 | stub.tap do |s| 53 | MeCab::Model.stub!(:create).and_return(s) 54 | s.stub!(:createTagger).and_return(parser_tagger || parser_tagger_stub) 55 | yield s if block_given? 56 | end 57 | end 58 | 59 | def make_node(surface, next_node = nil) 60 | stub.tap do |s| 61 | s.stub!(:surface).and_return(surface.to_s) 62 | s.stub!(:feature).and_return('part_of_speech,category1,*,*,*,*,*,*') 63 | s.stub!(:next).and_return(next_node) 64 | end 65 | end 66 | 67 | def parser 68 | require 'langue/japanese/parser' unless defined? Langue::Japanese::Parser 69 | Langue::Japanese::Parser.new 70 | end 71 | 72 | def noun(text) 73 | morphemes = parser.parse(text) 74 | Langue::Japanese::Noun.new(morphemes) 75 | end 76 | 77 | def adjective(text) 78 | morphemes = parser.parse(text) 79 | Langue::Japanese::Adjective.new(morphemes) 80 | end 81 | 82 | def adjectival_noun(text) 83 | morphemes = parser.parse(text) 84 | Langue::Japanese::AdjectivalNoun.new(morphemes) 85 | end 86 | 87 | def verb(text) 88 | morphemes = parser.parse(text) 89 | Langue::Japanese::Verb.new(morphemes) 90 | end 91 | 92 | def period(text) 93 | morphemes = parser.parse(text) 94 | Langue::Japanese::Period.new(morphemes) 95 | end 96 | -------------------------------------------------------------------------------- /spec/langue/japanese/inflector/inflections_spec.rb: -------------------------------------------------------------------------------- 1 | require 'langue/japanese/inflector/inflections' 2 | 3 | describe Langue::Japanese::Inflector::Inflections, '#inflection' do 4 | before do 5 | @inflections = described_class.new 6 | end 7 | 8 | it 'calls Langue::Japanese::Inflector::Inflection.new with the base suffix and the suffixes' do 9 | Langue::Japanese::Inflector::Inflection.should_receive(:new).with('suffix', 'form' => 'suffix') 10 | @inflections.inflection('classification', 'suffix', 'form' => 'suffix') 11 | end 12 | 13 | it 'defines the inflection' do 14 | @inflections.inflection('classification', 'suffix', 'form' => 'suffix') 15 | @inflections['classification'].should be_a(Langue::Japanese::Inflector::Inflection) 16 | end 17 | 18 | context 'in call #category' do 19 | it 'does not raise ArgumentError if defined the inflectional forms in just proportion' do 20 | lambda { 21 | @inflections.category 'form' do 22 | inflection 'classification', 'suffix', 'form' => 'suffix' 23 | end 24 | }.should_not raise_error(ArgumentError) 25 | end 26 | 27 | it 'raises ArgumentError if the inflectional forms is excess' do 28 | lambda { 29 | @inflections.category *%w(form1 form2 form3) do 30 | inflection 'classification', 'suffix' 31 | end 32 | }.should raise_error(ArgumentError, 'form1, form2 and form3 has not been defined') 33 | end 34 | 35 | it 'raises ArgumentError if the inflectional forms is inadequate' do 36 | lambda { 37 | @inflections.category 'form' do 38 | inflection 'classification', 'suffix', { 39 | 'form' => 'suffix', 40 | 'form1' => 'suffix1' 41 | } 42 | end 43 | }.should raise_error(ArgumentError, 'form1 should not be defined') 44 | end 45 | 46 | it 'raises ArgumentError if the inflectional forms is excess and inadequate' do 47 | lambda { 48 | @inflections.category *%w(form1 form2) do 49 | inflection 'classification', 'suffix', { 50 | 'form3' => 'suffix3', 51 | 'form4' => 'suffix4' 52 | } 53 | end 54 | }.should raise_error(ArgumentError, 'form1 and form2 has not been defined, and form3 and form4 should not be defined') 55 | end 56 | end 57 | end 58 | 59 | describe Langue::Japanese::Inflector::Inflections, '#category' do 60 | before do 61 | @inflections = described_class.new 62 | end 63 | 64 | it 'calls the block in scope of the instance' do 65 | matcher = equal(@inflections) 66 | @inflections.category { should matcher } 67 | end 68 | end 69 | 70 | describe Langue::Japanese::Inflector::Inflections, '#categorizing?' do 71 | before do 72 | @inflections = described_class.new 73 | end 74 | 75 | it 'returns false after initializing' do 76 | @inflections.should_not be_categorizing 77 | end 78 | 79 | it 'returns true in call #category' do 80 | matcher = be_categorizing 81 | @inflections.category { should matcher } 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /spec/langue/japanese/inflector/inflection_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'langue/japanese/inflector/inflection' 3 | 4 | describe Langue::Japanese::Inflector::Inflection, '#inflect' do 5 | before do 6 | suffixes = { 7 | 'form' => 'form_suffix', 8 | 'proc' => lambda { |options| options[:suffix] }, 9 | '連用タ接続' => 'ta_suffix', 10 | '連用テ接続' => 'te_suffix' 11 | } 12 | 13 | @inflection = described_class.new 'suffix', suffixes 14 | end 15 | 16 | it 'inflects the word to the inflectional form' do 17 | word = @inflection.inflect('body-suffix', 'form') 18 | word.should == 'body-form_suffix' 19 | end 20 | 21 | it 'adds value returning from calling of its Proc as suffix to the word if the inflectional form is an instance of Proc' do 22 | word = @inflection.inflect('body-suffix', 'proc', :suffix => 'proc_suffix') 23 | word.should == 'body-proc_suffix' 24 | end 25 | 26 | it 'raises ArgumentError if the word does not end with the base suffix' do 27 | lambda { @inflection.inflect('body-suffi', 'form') }.should raise_error(ArgumentError, 'the word does not end with "suffix"') 28 | end 29 | 30 | it 'raises ArgumentError if the inflectional form does not defined' do 31 | lambda { @inflection.inflect('body-suffix', 'form1') }.should raise_error(ArgumentError, '"form1" inflectional form does not defined in the inflection') 32 | end 33 | 34 | context 'with :following option' do 35 | it 'adds value of :following option to the word' do 36 | word = @inflection.inflect('body-suffix', 'form', :following => '-following') 37 | word.should == 'body-form_suffix-following' 38 | end 39 | 40 | it 'converts to "タ行" from "ダ行" in first character of the following word if the inflectional form is "連用タ接続" or "連用テ接続"' do 41 | { 42 | '連用タ接続' => 'ta_suffix', 43 | '連用テ接続' => 'te_suffix' 44 | }.each do |form, suffix| 45 | { 46 | 'だ' => 'た', 47 | 'じ' => 'ち', 48 | 'ぢ' => 'ち', 49 | 'で' => 'て', 50 | 'ど' => 'と' 51 | }.each do |following, converted_following| 52 | word = @inflection.inflect('body-suffix', form, :following => following) 53 | word.should == "body-#{suffix}#{converted_following}" 54 | end 55 | end 56 | end 57 | 58 | it 'converts to "ダ行" from "タ行" in first character of the following word if the inflectional form is "連用タ接続" or "連用テ接続"' do 59 | inflection = described_class.new('suffix', { 60 | '連用タ接続' => ['ta_suffix', true], 61 | '連用テ接続' => ['te_suffix', true] 62 | }) 63 | 64 | { 65 | '連用タ接続' => 'ta_suffix', 66 | '連用テ接続' => 'te_suffix' 67 | }.each do |form, suffix| 68 | { 69 | 'た' => 'だ', 70 | 'ち' => 'じ', 71 | 'て' => 'で', 72 | 'と' => 'ど' 73 | }.each do |following, converted_following| 74 | word = inflection.inflect('body-suffix', form, :following => following) 75 | word.should == "body-#{suffix}#{converted_following}" 76 | end 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/verb.rb: -------------------------------------------------------------------------------- 1 | require 'langue/word' 2 | require 'langue/japanese/words/prefix' 3 | require 'langue/japanese/words/attribute' 4 | require 'langue/japanese/words/classifier' 5 | 6 | module Langue 7 | module Japanese 8 | class Verb < ::Langue::Verb 9 | include Prefix 10 | 11 | def extract_prefix_morphemes 12 | size = 0 13 | 14 | if self.class.verb_prefix?(morphemes, size) 15 | size += 1 while self.class.verb_prefix?(morphemes, size) 16 | elsif self.class.noun_prefix?(morphemes, size) 17 | size += 1 while self.class.noun_prefix?(morphemes, size) 18 | end 19 | 20 | morphemes[0, size] 21 | end 22 | 23 | include Attribute 24 | 25 | has :progressive, :passive, :causative, :aggressive, :negative, :perfective, :imperative 26 | 27 | extend Classifier 28 | 29 | def self.take(morphemes, index) 30 | if first_verb?(morphemes, index) 31 | take_verb(morphemes, index) 32 | elsif verb_prefix?(morphemes, index) 33 | take_verb_with_prefix(morphemes, index) 34 | elsif first_noun?(morphemes, index) 35 | take_noun_conjunct_to_suru(morphemes, index) 36 | elsif noun_prefix?(morphemes, index) 37 | take_noun_with_prefix_conjunct_to_suru(morphemes, index) 38 | else 39 | 0 40 | end 41 | end 42 | 43 | def self.take_verb(morphemes, index) 44 | return 0 unless first_verb?(morphemes, index) 45 | take_following_verb(morphemes, index) 46 | end 47 | 48 | def self.take_verb_with_prefix(morphemes, index) 49 | size = 0 50 | size += 1 while verb_prefix?(morphemes, index + size) 51 | return 0 unless size > 0 52 | next_size = take_verb(morphemes, index + size) 53 | next_size > 0 ? size + next_size : 0 54 | end 55 | 56 | def self.take_noun_conjunct_to_suru(morphemes, index) 57 | size = 0 58 | size += 1 while following_noun?(morphemes, index + size) 59 | return 0 unless size > 0 60 | return 0 unless noun_conjunct_to_suru?(morphemes, index + size - 1) 61 | return 0 unless suru_verb?(morphemes, index + size) 62 | size + take_following_verb(morphemes, index + size) 63 | end 64 | 65 | def self.take_noun_with_prefix_conjunct_to_suru(morphemes, index) 66 | size = 0 67 | size += 1 while noun_prefix?(morphemes, index + size) 68 | return 0 unless size > 0 69 | next_size = take_noun_conjunct_to_suru(morphemes, index + size) 70 | next_size > 0 ? size + next_size : 0 71 | end 72 | 73 | def self.take_following_verb(morphemes, index) 74 | size = 1 75 | size += 1 while following_verb?(morphemes, index + size) 76 | size += 1 while final_particle?(morphemes, index + size) 77 | size 78 | end 79 | 80 | def key_morpheme 81 | unless instance_variable_defined?(:@key_morpheme) 82 | @key_morpheme = if empty? 83 | nil 84 | else 85 | index = size - 1 86 | index -= 1 while !self.class.body_verb?(morphemes, index) 87 | self[index] 88 | end 89 | end 90 | 91 | @key_morpheme 92 | end 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/adjective_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/adjective' 4 | 5 | describe Langue::Japanese::Adjective do 6 | it 'inherits Langue::Adjective' do 7 | described_class.superclass.should == Langue::Adjective 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Adjective, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes an adjective' do 20 | @pairs = { 21 | '可愛いこと' => 1, 22 | 'かっこいいこと' => 1, 23 | '会話だ' => 0, 24 | '話すこと' => 0 25 | } 26 | end 27 | 28 | it 'takes an adjective with prefix' do 29 | @pairs = { 30 | 'くそ可愛いこと' => 2, 31 | 'くそくそかっこいいこと' => 3, 32 | 'くそ会話だ' => 0 33 | } 34 | end 35 | 36 | it 'takes an adjective with suffix' do 37 | @pairs = { 38 | '可愛いっぽいこと' => 2 39 | } 40 | end 41 | 42 | it 'takes a successive adjective' do 43 | @pairs = { 44 | '可愛がたいこと' => 2 45 | } 46 | end 47 | 48 | it 'takes a negative adjective' do 49 | @pairs = { 50 | '可愛くないこと' => 2, 51 | 'かっこよくないこと' => 2 52 | } 53 | end 54 | 55 | it 'takes a perfective adjective' do 56 | @pairs = { 57 | '可愛かったこと' => 2, 58 | 'かっこよかったこと' => 2 59 | } 60 | end 61 | 62 | it 'takes a complex adjective' do 63 | @pairs = { 64 | 'くそ可愛がたくなかったこと' => 5, 65 | 'クソかっこよくないこと' => 3, 66 | '美しくなかったこと' => 3, 67 | '厳しいっぽくなかったこと' => 4 68 | } 69 | end 70 | 71 | it 'takes an adjective by other' do 72 | @pairs = { 73 | '可愛いでしょう' => 3 74 | } 75 | end 76 | end 77 | 78 | describe Langue::Japanese::Adjective, '#key_morpheme' do 79 | it 'returns the categorematic adjective or the noncategorematic adjective' do 80 | { 81 | '可愛い' => 0, 82 | '可愛っぽい' => 0, 83 | '可愛くない' => 0, 84 | '可愛がたい' => 1 85 | }.each do |text, index| 86 | word = adjective(text) 87 | word.key_morpheme.should == word[index] 88 | end 89 | end 90 | 91 | context 'with an empty word' do 92 | it 'returns nil' do 93 | word = described_class.new 94 | word.key_morpheme.should be_nil 95 | end 96 | end 97 | 98 | context 'with word that is not adjective' do 99 | it 'raises Langue::Japanese::InvalidWord' do 100 | %w(会話 話す).each do |text| 101 | word = adjective(text) 102 | lambda { word.key_morpheme }.should raise_error(Langue::Japanese::InvalidWord, %("#{text}" is invalid a word as an adjective)) 103 | end 104 | end 105 | end 106 | end 107 | 108 | describe Langue::Japanese::Adjective, '#prefix' do 109 | it 'returns the prefix' do 110 | adjective('くそくそ可愛っぽくない').prefix.should == 'くそくそ' 111 | end 112 | end 113 | 114 | describe Langue::Japanese::Adjective, '#body' do 115 | it 'returns the text with the prefix' do 116 | adjective('くそくそ可愛っぽくない').body.should == '可愛い' 117 | end 118 | end 119 | 120 | describe Langue::Japanese::Adjective, '#negative?' do 121 | it 'returns true if it is negative' do 122 | adjective('可愛くない').should be_negative 123 | end 124 | 125 | it 'returns false if it is not negative' do 126 | adjective('可愛い').should_not be_negative 127 | end 128 | end 129 | 130 | describe Langue::Japanese::Adjective, '#perfective?' do 131 | it 'returns true if it is perfective' do 132 | adjective('可愛かった').should be_perfective 133 | end 134 | 135 | it 'returns false if it is not perfective' do 136 | adjective('可愛い').should_not be_perfective 137 | end 138 | end 139 | -------------------------------------------------------------------------------- /spec/langue/japanese/structurer_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/structurer' 4 | require 'yaml' 5 | 6 | describe Langue::Japanese::Structurer, '::WORD_CLASSES' do 7 | before do 8 | @word_classes = Langue::Japanese::Structurer::WORD_CLASSES 9 | end 10 | 11 | it 'has the word classes' do 12 | @word_classes.should == [ 13 | Langue::Japanese::Period, 14 | Langue::Japanese::Interjection, 15 | Langue::Japanese::Determiner, 16 | Langue::Japanese::Conjunction, 17 | Langue::Japanese::Particle, 18 | Langue::Japanese::Adverb, 19 | Langue::Japanese::Verb, 20 | Langue::Japanese::Adjective, 21 | Langue::Japanese::AdjectivalNoun, 22 | Langue::Japanese::Pronoun, 23 | Langue::Japanese::Noun 24 | ] 25 | end 26 | 27 | it 'has take method in all the word classes' do 28 | @word_classes.each do |word_class| 29 | word_class.should be_respond_to(:take) 30 | end 31 | end 32 | end 33 | 34 | describe Langue::Japanese::Structurer, '#initialize' do 35 | it 'sets an instance of Langue::Japanese::Logging::NullLogger to @logger' do 36 | structurer = described_class.new 37 | logger = structurer.instance_eval { @logger } 38 | logger.should be_a(Langue::Japanese::Logging::NullLogger) 39 | end 40 | 41 | context 'with logger option' do 42 | it 'sets the value of logger option to @logger' do 43 | structurer = described_class.new(:logger => 'logger') 44 | logger = structurer.instance_eval { @logger } 45 | logger.should == 'logger' 46 | end 47 | end 48 | end 49 | 50 | describe Langue::Japanese::Structurer, '#structure' do 51 | before :all do 52 | @parser = parser 53 | @morphemes = @parser.parse('今日は妹と一緒にお買い物してきたよ。楽しかった〜') 54 | @word_classes = Langue::Japanese::Structurer::WORD_CLASSES 55 | end 56 | 57 | before do 58 | @structurer = described_class.new 59 | end 60 | 61 | it 'returns an instance of Langue::Text' do 62 | text = @structurer.structure(@morphemes) 63 | text.should be_a Langue::Text 64 | end 65 | 66 | it 'returns valid text' do 67 | text = @structurer.structure(@morphemes) 68 | text.should be_valid 69 | end 70 | 71 | it 'returns sentences in the text' do 72 | text = @structurer.structure(@morphemes) 73 | text.should have(2).items 74 | end 75 | 76 | it 'returns words in the sentences' do 77 | text = @structurer.structure(@morphemes) 78 | text[0].should have(8).items 79 | text[1].should have(2).items 80 | end 81 | 82 | YAML.load_file(File.join(File.dirname(__FILE__), 'data.yaml')).each do |data| 83 | input = data['text'] 84 | sentences = data['sentences'] 85 | 86 | it "extracts expected words from #{input.size < 10 ? input : input[0..7] + '...'}" do 87 | morphemes = @parser.parse(input) 88 | text = @structurer.structure(morphemes) 89 | text.should have(sentences.size).items 90 | 91 | text.each_with_index do |sentence, index| 92 | sentence = sentence.select { |word| !word.instance_of?(Langue::Word) } 93 | words = sentences[index] 94 | sentence.should have(words.size).items 95 | 96 | words.zip(sentence).each do |pair| 97 | pair[1].text.should == pair[0][0] 98 | pair[1].class.name.split('::').last.should == pair[0][1] 99 | next unless pair[0][2] 100 | 101 | pair[0][2].each do |name, value| 102 | if name.downcase == 'attributes' 103 | value.each do |attribute| 104 | pair[1].__send__("#{attribute}?").should be_true 105 | end 106 | else 107 | got = pair[1].__send__(name) 108 | 109 | if TrueClass === value 110 | got.should be_true 111 | elsif FalseClass === value 112 | got.should be_false 113 | else 114 | got.should == value 115 | end 116 | end 117 | end 118 | end 119 | end 120 | end 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/attribute.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'langue/japanese/words/morpheme_filter' 3 | 4 | module Langue 5 | module Japanese 6 | module Attribute 7 | def self.included(object) 8 | object.extend(ClassMethods) 9 | object.class_eval { include MorphemeFilter } 10 | object.filter { |word, morphemes| word.empty? ? morphemes : morphemes[0..morphemes.index(word.key_morpheme)] } 11 | end 12 | 13 | module ClassMethods 14 | def has(*attrs) 15 | attrs.each do |attr| 16 | define_method("#{attr}?") do 17 | @attrs ||= {} 18 | @attrs[attr] = !!__send__("include_#{attr}?") unless @attrs.key?(attr) 19 | @attrs[attr] 20 | end 21 | end 22 | end 23 | end 24 | 25 | if RUBY_VERSION.to_f < 1.9 26 | def index(value = nil) 27 | if value 28 | super 29 | else 30 | each_with_index { |morpheme, index| return index if yield morpheme } 31 | nil 32 | end 33 | end 34 | end 35 | 36 | private 37 | 38 | def include_progressive? 39 | if noncategorematic_verb_index(%w(てる でる とる どる)) 40 | true 41 | elsif index = noncategorematic_verb_index(['いる']) 42 | morphemes.at(index - 1) { |m| m.classified?('助詞', '接続助詞') && %w(て で).include?(m.root_form) } 43 | end 44 | end 45 | 46 | def include_passive? 47 | verb_suffix_index(%w(れる られる)) 48 | end 49 | 50 | def include_causative? 51 | verb_suffix_index(%w(せる させる)) 52 | end 53 | 54 | def include_aggressive? 55 | auxiliary_verb_index('特殊・タイ') 56 | end 57 | 58 | def include_negative? 59 | if nai_auxiliary_verb_count.odd? 60 | true 61 | elsif index = auxiliary_verb_index('特殊・ヌ') 62 | morphemes.at(index - 1) { |m| m.inflection_type == '未然形' } 63 | elsif index = auxiliary_verb_index('特殊・マス') { |m| m.inflection_type == '未然形' } 64 | morphemes.at(index + 1) { |m| m.classified?('助動詞') && m.root_form == 'ん' } 65 | else 66 | na_final_particle_with_conclusive? 67 | end 68 | end 69 | 70 | def include_perfective? 71 | if auxiliary_verb_index('特殊・タ') 72 | true 73 | elsif index = index { |m| m.classified?('助動詞') && m.root_form == 'ぬ' } 74 | morphemes.at(index - 1) { |m| m.inflection_type == '連用形' } 75 | end 76 | end 77 | 78 | def include_imperative? 79 | last = reverse.drop_while { |m| m.classified?('助詞', '終助詞') }.first 80 | 81 | (last and last.inflection_type =~ /^命令/) || 82 | na_final_particle_with_conclusive? || 83 | na_final_particle_with_conjunctive? || 84 | ta_conjunctive_particle? 85 | end 86 | 87 | def noncategorematic_verb_index(root_forms) 88 | index { |m| m.classified?('動詞', '非自立') && root_forms.include?(m.root_form) } 89 | end 90 | 91 | def auxiliary_verb_index(inflection) 92 | index { |m| m.classified?('助動詞') && m.inflected?(inflection) && (block_given? ? yield(m) : true) } 93 | end 94 | 95 | def verb_suffix_index(root_forms) 96 | index { |m| m.classified?('動詞', '接尾') && root_forms.include?(m.root_form) } 97 | end 98 | 99 | def nai_auxiliary_verb_count 100 | count { |m| m.classified?('助動詞') && m.inflected?('特殊・ナイ') } 101 | end 102 | 103 | def ta_conjunctive_particle? 104 | index = size - 1 105 | index -= 1 while morphemes.at(index) { |m| m.classified?('助詞', '終助詞') } 106 | morphemes.at(index) { |m| m.classified?('助詞', '接続助詞') && %w(て で).include?(m.root_form) } 107 | end 108 | 109 | def na_final_particle_with_conjunctive? 110 | na_final_particle? && 111 | morphemes.at(-2) { |m| m.classified?('動詞') && m.inflection_type == '連用形' } 112 | end 113 | 114 | def na_final_particle_with_conclusive? 115 | na_final_particle? && 116 | morphemes.at(-2) { |m| m.classified?('動詞') && m.inflection_type == '基本形' } 117 | end 118 | 119 | def na_final_particle? 120 | morphemes.at(-1) { |m| m.classified?('助詞', '終助詞') && m.root_form == 'な' } 121 | end 122 | end 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /lib/langue/japanese/words/classifier.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | module Langue 3 | module Japanese 4 | module Classifier 5 | { 6 | 7 | # noun 8 | :noun => %w(名詞), 9 | :noncategorematic_noun => %w(名詞 非自立), 10 | :noun_conjunct_to_suru => %w(名詞 サ変接続), 11 | :adverbable_noun => %w(名詞 副詞可能), 12 | :adjective_stem_noun => %w(名詞 形容動詞語幹), 13 | :pronoun => %w(名詞 代名詞), 14 | 15 | # adjective 16 | :categorematic_adjective => %w(形容詞 自立), 17 | :noncategorematic_adjective => %w(形容詞 非自立), 18 | 19 | # verb 20 | :categorematic_verb => %w(動詞 自立), 21 | :noncategorematic_verb => %w(動詞 非自立), 22 | 23 | # adverb 24 | :adverb => %w(副詞), 25 | 26 | # auxiliary verb 27 | :auxiliary_verb => %w(助動詞), 28 | 29 | # particle 30 | :particle => %w(助詞), 31 | :conjunctive_particle => %w(助詞 接続助詞), 32 | 33 | # conjunction 34 | :conjunction => %w(接続詞), 35 | 36 | # determiner 37 | :determiner => %w(連体詞), 38 | 39 | # interjection 40 | :interjection => %w(感動詞), 41 | 42 | # prefix 43 | :noun_prefix => %w(接頭詞 名詞接続), 44 | :adjective_prefix => %w(接頭詞 形容詞接続), 45 | :verb_prefix => %w(接頭詞 動詞接続), 46 | 47 | # suffix 48 | :noun_suffix => %w(名詞 接尾), 49 | :adjective_stem_suffix => %w(名詞 接尾 形容動詞語幹), 50 | :adjective_suffix => %w(形容詞 接尾), 51 | :verb_suffix => %w(動詞 接尾), 52 | 53 | # symbol 54 | :symbol => %w(記号), 55 | :alphabet => %w(記号 アルファベット) 56 | 57 | }.each do |category, categories| 58 | define_method("#{category}?") do |morphemes, index| 59 | morphemes.at(index) { |m| m.classified?(*categories) } 60 | end 61 | end 62 | 63 | def final_particle?(morphemes, index) 64 | morphemes.at(index) do |m| 65 | m.classified?('助詞', '終助詞') || 66 | m.classified?('助詞', '副助詞/並立助詞/終助詞') 67 | end 68 | end 69 | 70 | def first_noun?(morphemes, index) 71 | noun?(morphemes, index) && 72 | !pronoun?(morphemes, index) && 73 | !adverbable_noun?(morphemes, index) && 74 | !noun_suffix?(morphemes, index) && 75 | !noncategorematic_noun?(morphemes, index) 76 | end 77 | 78 | def first_verb?(morphemes, index) 79 | categorematic_verb?(morphemes, index) && morphemes.at(index) do |m| 80 | !%w(思う おもう).include?(m.root_form) 81 | end 82 | end 83 | 84 | def first_adjective?(morphemes, index) 85 | categorematic_adjective?(morphemes, index) 86 | end 87 | 88 | def following_noun?(morphemes, index) 89 | noun?(morphemes, index) && 90 | !pronoun?(morphemes, index) && 91 | !adverbable_noun?(morphemes, index) 92 | end 93 | 94 | def following_adjective?(morphemes, index) 95 | (noncategorematic_adjective?(morphemes, index) || adjective_suffix?(morphemes, index)) || 96 | auxiliary_verb?(morphemes, index) 97 | end 98 | 99 | def following_verb?(morphemes, index) 100 | noncategorematic_verb?(morphemes, index) || 101 | verb_suffix?(morphemes, index) || 102 | auxiliary_verb?(morphemes, index) || 103 | ta_conjunctive_particle?(morphemes, index) 104 | end 105 | 106 | def following_symbol?(morphemes, index) 107 | alphabet?(morphemes, index) 108 | end 109 | 110 | def suru_verb?(morphemes, index) 111 | categorematic_verb?(morphemes, index) && morphemes.at(index) { |m| m.inflected?('サ変・スル') } 112 | end 113 | 114 | def body_verb?(morphemes, index) 115 | categorematic_verb?(morphemes, index) || noncategorematic_verb?(morphemes, index) && !ta_verb?(morphemes, index) && !ra_verb?(morphemes, index) 116 | end 117 | 118 | def ta_verb?(morphemes, index) 119 | noncategorematic_verb?(morphemes, index) && morphemes.at(index) do |m| 120 | %w(いる てる でる とる どる ちゃう じゃう).include?(m.root_form) 121 | end 122 | end 123 | 124 | def ra_verb?(morphemes, index) 125 | noncategorematic_verb?(morphemes, index) && morphemes.at(index) { |m| m.inflected?('五段・ラ行特殊') } 126 | end 127 | 128 | def body_adjective?(morphemes, index) 129 | categorematic_adjective?(morphemes, index) || noncategorematic_adjective?(morphemes, index) 130 | end 131 | 132 | def ta_conjunctive_particle?(morphemes, index) 133 | conjunctive_particle?(morphemes, index) && morphemes.at(index) do |m| 134 | %w(て で たって).include?(m.root_form) 135 | end 136 | end 137 | end 138 | end 139 | end 140 | -------------------------------------------------------------------------------- /spec/langue/japanese/data.yaml: -------------------------------------------------------------------------------- 1 | - 2 | text: 今日は妹と一緒にお買い物してきたよ。楽しかった〜 3 | sentences: 4 | - 5 | - [今日, Noun] 6 | - [は, Particle] 7 | - [妹, Noun] 8 | - [と, Particle] 9 | - [一緒, Noun] 10 | - [に, Particle] 11 | - - お買い物してきたよ 12 | - Verb 13 | - body: 買い物してくる 14 | prefix: お 15 | attributes: [perfective] 16 | - [。, Period] 17 | - 18 | - - 楽しかった 19 | - Adjective 20 | - body: 楽しい 21 | attributes: [perfective] 22 | 23 | - 24 | text: 例の女子会が延期になってちょっとホッとしている 25 | sentences: 26 | - 27 | - [例, Noun] 28 | - [の, Particle] 29 | - [女子会, Noun] 30 | - [が, Particle] 31 | - [延期, Noun] 32 | - [に, Particle] 33 | - [なって, Verb] 34 | - [ちょっとホッ, Adverb] 35 | - [と, Particle] 36 | - [している, Verb] 37 | 38 | - 39 | text: こんなに部屋が寒くてはインターネットもままならぬ 40 | sentences: 41 | - 42 | - [こんなに, Adverb] 43 | - [部屋, Noun] 44 | - [が, Particle] 45 | - - 寒く 46 | - Adjective 47 | - body: 寒い 48 | - [は, Particle] 49 | - [インターネット, Noun] 50 | - [も, Particle] 51 | - [まま, Adverb] 52 | - [ならぬ, Verb] 53 | 54 | - 55 | text: 牛乳って意外と甘い? 56 | sentences: 57 | - 58 | - [牛乳, Noun] 59 | - [って, Particle] 60 | - [意外と, Adverb] 61 | - - 甘い 62 | - Adjective 63 | - body: 甘い 64 | - [?, Period] 65 | 66 | - 67 | text: むしろ精神的疾患とは…… 68 | sentences: 69 | - 70 | - [むしろ, Adverb] 71 | - [精神的疾患, Noun] 72 | - [とは, Particle] 73 | - [……, Period] 74 | 75 | - 76 | text: 情報系大学生なら卒業までに応用情報レベルの知識を習っていると思うのだけども. 77 | sentences: 78 | - 79 | - [情報系大学生, Noun] 80 | - [卒業, Noun] 81 | - [までに, Particle] 82 | - [応用情報レベル, Noun] 83 | - [の, Particle] 84 | - [知識, Noun] 85 | - [を, Particle] 86 | - - 習っている 87 | - Verb 88 | - body: 習う 89 | attributes: [progressive] 90 | - [と, Particle] 91 | - [., Period] 92 | 93 | - 94 | text: プログラマーの資格を持つ息子が面接に全て落ちました。理系でも旧帝じゃないとダメなのでしょうか? 95 | sentences: 96 | - 97 | - [プログラマー, Noun] 98 | - [の, Particle] 99 | - [資格, Noun] 100 | - [を, Particle] 101 | - - 持つ 102 | - Verb 103 | - body: 持つ 104 | - [息子, Noun] 105 | - [が, Particle] 106 | - [面接, Noun] 107 | - [に, Particle] 108 | - [全て, Noun] 109 | - - 落ちました 110 | - Verb 111 | - body: 落ちる 112 | attributes: [perfective] 113 | - [。, Period] 114 | - 115 | - [理系, Noun] 116 | - [でも, Particle] 117 | - [旧帝, Noun] 118 | - [じゃ, Particle] 119 | - [ダメ, AdjectivalNoun] 120 | - [か, Particle] 121 | - [?, Period] 122 | 123 | - 124 | text: ちゃんと病院いこうね…。はい…。 125 | sentences: 126 | - 127 | - [ちゃんと, Adverb] 128 | - [病院, Noun] 129 | - - いこうね 130 | - Verb 131 | - body: いく 132 | - […。, Period] 133 | - 134 | - [はい, Interjection] 135 | - […。, Period] 136 | 137 | - 138 | text: んー、お昼がスープパスタだけとか。。。あふんあふん。。。後で絶対お腹すくなー。でも今あんま食べる気しにゃい。。。 139 | sentences: 140 | - 141 | - [ん, Particle] 142 | - [お昼, Noun] 143 | - [が, Particle] 144 | - [スープパスタ, Noun] 145 | - [だけとか, Particle] 146 | - [。。。, Period] 147 | - 148 | - [あふん, Verb] 149 | - [ふん, Interjection] 150 | - [。。。, Period] 151 | - 152 | - [後で, Adverb] 153 | - [絶対, Noun] 154 | - [お腹, Noun] 155 | - - すく 156 | - Adjective 157 | - body: すい 158 | - [なー, Particle] 159 | - [。, Period] 160 | - 161 | - [でも, Conjunction] 162 | - [今あんま, Noun] 163 | - - 食べる 164 | - Verb 165 | - body: 食べる 166 | - [しにゃい, Verb] 167 | - [。。。, Period] 168 | 169 | - 170 | text: iPhone 4Sにただで替えられるって聞いたけど、本当に使うかは疑問なので…… 171 | sentences: 172 | - 173 | - [iPhone4S, Noun] 174 | - [に, Particle] 175 | - [ただ, Noun] 176 | - [で, Particle] 177 | - - 替えられる 178 | - Verb 179 | - body: 替える 180 | attributes: [passive] 181 | - [って, Particle] 182 | - - 聞いた 183 | - Verb 184 | - body: 聞く 185 | attributes: [perfective] 186 | - [本当に, Adverb] 187 | - - 使うか 188 | - Verb 189 | - body: 使う 190 | - [は, Particle] 191 | - [疑問, Noun] 192 | - [……, Period] 193 | 194 | - 195 | text: 俺のためにご奉仕しろ! 196 | sentences: 197 | - 198 | - [俺, Pronoun] 199 | - [の, Particle] 200 | - [に, Particle] 201 | - - ご奉仕しろ 202 | - Verb 203 | - body: 奉仕する 204 | prefix: ご 205 | attributes: [imperative] 206 | - [!, Period] 207 | 208 | - 209 | text: 風と共に去らぬ 210 | sentences: 211 | - 212 | - [風, Noun] 213 | - [と共に, Particle] 214 | - - 去らぬ 215 | - Verb 216 | - body: 去る 217 | attributes: [negative] 218 | -------------------------------------------------------------------------------- /spec/langue/japanese/language_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'langue/japanese/language' 3 | 4 | describe Langue::Japanese::Language do 5 | it 'is an instance of Class' do 6 | described_class.should be_an_instance_of(Class) 7 | end 8 | 9 | it 'extends Langue::Language' do 10 | described_class.superclass.should == Langue::Language 11 | end 12 | end 13 | 14 | describe Langue::Japanese::Language, '#parser' do 15 | before do 16 | @language = described_class.new(:key => 'value') 17 | end 18 | 19 | it 'calls Langue::Japanese::Parser.new with the options' do 20 | parser_stub 21 | Langue::Japanese::Parser.should_receive(:new).with(:key => 'value') 22 | @language.parser 23 | end 24 | 25 | it 'returns an instance of Langue::Japanese::Parser' do 26 | parser = parser_stub 27 | @language.parser.should == parser 28 | end 29 | end 30 | 31 | describe Langue::Japanese::Language, '#shaper' do 32 | before do 33 | @language = described_class.new(:key => 'value') 34 | end 35 | 36 | it 'calls Langue::Japanese::Shaper.new with the options' do 37 | shaper_stub 38 | Langue::Japanese::Shaper.should_receive(:new).with(:key => 'value') 39 | @language.shaper 40 | end 41 | 42 | it 'returns an instance of Langue::Japanese::Shaper' do 43 | shaper = shaper_stub 44 | @language.shaper.should == shaper 45 | end 46 | end 47 | 48 | describe Langue::Japanese::Language, '#structurer' do 49 | before do 50 | @language = described_class.new(:key => 'value') 51 | end 52 | 53 | it 'calls Langue::Japanese::Structurer.new with the options' do 54 | structurer_stub 55 | Langue::Japanese::Structurer.should_receive(:new).with(:key => 'value') 56 | @language.structurer 57 | end 58 | 59 | it 'returns an instance of Langue::Japanese::Structurer' do 60 | structurer = structurer_stub 61 | @language.structurer.should == structurer 62 | end 63 | end 64 | 65 | describe Langue::Japanese::Language, '#inflector' do 66 | before do 67 | @language = described_class.new(:key => 'value') 68 | end 69 | 70 | it 'calls Langue::Japanese::Inflector.new with the options' do 71 | inflector_stub 72 | Langue::Japanese::Inflector.should_receive(:new).with(:key => 'value') 73 | @language.inflector 74 | end 75 | 76 | it 'returns an instance of Langue::Japanese::Inflector' do 77 | inflector = inflector_stub 78 | @language.inflector.should == inflector 79 | end 80 | end 81 | 82 | describe Langue::Japanese::Language, '#parse' do 83 | before do 84 | @language = described_class.new(:key => 'value') 85 | end 86 | 87 | it 'calls parse method of parser with a text' do 88 | parser_stub do |m| 89 | m.should_receive(:parse).with('text') 90 | end 91 | 92 | @language.parse('text') 93 | end 94 | 95 | it 'returns the value returning from Langue::Japanese::Parser#parse' do 96 | parser_stub 97 | @language.parse('text').should == 'value returning from parse method' 98 | end 99 | end 100 | 101 | describe Langue::Japanese::Language, '#shape_person_name' do 102 | before do 103 | @language = described_class.new(:key => 'value') 104 | end 105 | 106 | it 'calls shape_person_name method of shaper with morphemes' do 107 | shaper_stub do |m| 108 | m.should_receive(:shape_person_name).with('morphemes', 'Akane') 109 | end 110 | 111 | @language.shape_person_name('morphemes', 'Akane') 112 | end 113 | 114 | it 'returns the value returning from Langue::Japanese::Shaper#shape_person_name' do 115 | shaper_stub 116 | @language.shape_person_name('morphemes', 'Akane').should == 'value returning from shape_person_name method' 117 | end 118 | end 119 | 120 | describe Langue::Japanese::Language, '#structure' do 121 | before do 122 | @language = described_class.new(:key => 'value') 123 | end 124 | 125 | it 'calls structure method of structurer with morphemes' do 126 | structurer_stub do |m| 127 | m.should_receive(:structure).with('morphemes') 128 | end 129 | 130 | @language.structure('morphemes') 131 | end 132 | 133 | it 'returns the value returning from Langue::Japanese::Structurer#structure' do 134 | structurer_stub 135 | @language.structure('morphemes').should == 'value returning from structure method' 136 | end 137 | end 138 | 139 | describe Langue::Japanese::Language, '#inflect' do 140 | before do 141 | @language = described_class.new(:key => 'value') 142 | end 143 | 144 | it 'calls #inflect of the inflector with the inflectional classification, the word, the inflectional form and the options' do 145 | inflector_stub do |m| 146 | m.should_receive(:inflect).with('classification', 'word', 'form', :key => 'value') 147 | end 148 | 149 | @language.inflect('classification', 'word', 'form', :key => 'value') 150 | end 151 | 152 | it 'returns the value returning from Langue::Japanese::Inflector#inflect' do 153 | inflector_stub 154 | @language.inflect('classification', 'word', 'form', :key => 'value').should == 'value returning from #inflect' 155 | end 156 | end 157 | -------------------------------------------------------------------------------- /spec/langue/japanese/words/verb_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'langue/japanese/words/verb' 4 | 5 | describe Langue::Japanese::Verb do 6 | it 'inherits Langue::Verb' do 7 | described_class.superclass.should == Langue::Verb 8 | end 9 | end 10 | 11 | describe Langue::Japanese::Verb, '.take' do 12 | after do 13 | @pairs.each do |text, size| 14 | morphemes = parser.parse(text) 15 | described_class.take(morphemes, 0).should == size 16 | end 17 | end 18 | 19 | it 'takes a verb' do 20 | @pairs = { 21 | '話すこと' => 1, 22 | '喋ること' => 1, 23 | '会話だ' => 0, 24 | 'かわいいこと' => 0 25 | } 26 | end 27 | 28 | it 'takes a verb with prefix' do 29 | @pairs = { 30 | 'ぶっ話すこと' => 2, 31 | 'ぶっぶち話すこと' => 3, 32 | 'ぶっ会話だ' => 0, 33 | 'ぶっかわいいこと' => 0 34 | } 35 | end 36 | 37 | it 'takes a noun conjunct to suru-verb as a verb' do 38 | @pairs = { 39 | '会話すること' => 2, 40 | '連絡すること' => 2, 41 | '会話だ' => 0 42 | } 43 | end 44 | 45 | it 'takes a noun conjunct to suru-verb with prefix as a verb' do 46 | @pairs = { 47 | 'ご連絡すること' => 3, 48 | '超反連絡すること' => 4, 49 | 'ご連絡だ' => 0, 50 | '反超すること' => 0 51 | } 52 | end 53 | 54 | it 'takes a verb with suffix' do 55 | @pairs = { 56 | '話されること' => 2, 57 | 'ぶっ放されること' => 3, 58 | '会話されること' => 3, 59 | 'ご連絡されること' => 4, 60 | '聞かせること' => 2, 61 | 'ぶっ聞かせること' => 3 62 | } 63 | end 64 | 65 | it 'takes a verb with noncategorematic verb' do 66 | @pairs = { 67 | '話し続けること' => 2, 68 | 'ぶっ話し続けること' => 3, 69 | '会話し続けること' => 3, 70 | 'ご連絡し続けること' => 4, 71 | 'いる' => 0 72 | } 73 | end 74 | 75 | it 'takes a verb with conjunctive particle' do 76 | @pairs = { 77 | '話していること' => 3, 78 | 'ぶっ話していること' => 4, 79 | '会話していること' => 4, 80 | 'ご連絡していること' => 5, 81 | '遊んで!' => 2, 82 | '話さなかったってさ' => 4, 83 | '話して欲しいこと' => 2, 84 | '話しこそすれ' => 1 85 | } 86 | end 87 | 88 | it 'takes a verb with auxiliary verb' do 89 | @pairs = { 90 | '話したいこと' => 2, 91 | '話したこと' => 2, 92 | '話さないこと' => 2, 93 | '話さんこと' => 2, 94 | '話します' => 2, 95 | '話しません' => 3, 96 | '話すでしょう' => 3, 97 | '話しちゃう' => 2 98 | } 99 | end 100 | 101 | it 'takes a verb with final particle' do 102 | @pairs = { 103 | '話すな!' => 2, 104 | '話すか?' => 2, 105 | '話すかしら?' => 2, 106 | '話すよ!' => 2 107 | } 108 | end 109 | 110 | it 'takes a complex verb' do 111 | @pairs = { 112 | '話し続けていたくなかったこと' => 7, 113 | 'ぶっ話し続けていたくなかったこと' => 8, 114 | '会話し続けていたくなかったこと' => 8, 115 | 'ご連絡し続けていたくなかったこと' => 9, 116 | 'ご連絡し続けていたくなかったか?' => 10 117 | } 118 | end 119 | 120 | it 'does not take special verbs' do 121 | @pairs = { 122 | '思い続けていること' => 0, 123 | 'ぶっ思います' => 0, 124 | 'おもわれたいこと' => 0, 125 | 'ぶちおもわない' => 0 126 | } 127 | end 128 | end 129 | 130 | describe Langue::Japanese::Verb, '#key_morpheme' do 131 | it 'returns the categorematic verb or the noncategorematic verb' do 132 | { 133 | '話す' => 0, 134 | '話し続けている' => 1, 135 | '話される' => 0, 136 | '話して' => 0, 137 | '話してる' => 0, 138 | '話している' => 0, 139 | '話しとる' => 0, 140 | '話しちゃう' => 0, 141 | '話したって' => 0 142 | }.each do |text, index| 143 | word = verb(text) 144 | word.key_morpheme.should == word[index] 145 | end 146 | end 147 | 148 | context 'with an empty word' do 149 | it 'returns nil' do 150 | word = described_class.new 151 | word.key_morpheme.should be_nil 152 | end 153 | end 154 | end 155 | 156 | describe Langue::Japanese::Verb, '#prefix' do 157 | it 'returns the prefix' do 158 | verb('ぶっぶち話さない').prefix.should == 'ぶっぶち' 159 | verb('超ご連絡しない').prefix.should == '超ご' 160 | end 161 | end 162 | 163 | describe Langue::Japanese::Verb, '#body' do 164 | it 'returns the text without the attributes' do 165 | verb('話したくなかった').body.should == '話す' 166 | verb('連絡したくなかった').body.should == '連絡する' 167 | end 168 | 169 | it 'returns the text without the prefix' do 170 | verb('ぶっぶち話す').body.should == '話す' 171 | verb('超ご連絡する').body.should == '連絡する' 172 | end 173 | 174 | it 'returns the text without the progressive verb' do 175 | verb('話している').body.should == '話す' 176 | verb('話してる').body.should == '話す' 177 | end 178 | 179 | it 'returns the text without the ra verb' do 180 | verb('話してください').body.should == '話す' 181 | end 182 | end 183 | 184 | describe Langue::Japanese::Verb, '#progressive?' do 185 | it 'returns true if it is progressive' do 186 | verb('話している').should be_progressive 187 | verb('話してる').should be_progressive 188 | verb('話しとる').should be_progressive 189 | verb('富んでいる').should be_progressive 190 | verb('富んでる').should be_progressive 191 | verb('富んどる').should be_progressive 192 | end 193 | 194 | it 'returns false if it is not progressive' do 195 | verb('話されたくなかった').should_not be_progressive 196 | verb('話しちゃう').should_not be_progressive 197 | verb('富んじゃう').should_not be_progressive 198 | end 199 | end 200 | 201 | describe Langue::Japanese::Verb, '#passive?' do 202 | it 'returns true if it is passive' do 203 | verb('話される').should be_passive 204 | verb('富んでられる').should be_passive 205 | end 206 | 207 | it 'returns false if it is not passive' do 208 | verb('話していたくなかった').should_not be_passive 209 | end 210 | end 211 | 212 | describe Langue::Japanese::Verb, '#causative?' do 213 | it 'returns true if it is causative' do 214 | verb('聞かせる').should be_causative 215 | verb('続けさせる').should be_causative 216 | end 217 | 218 | it 'returns false if it is not causative' do 219 | verb('聞かれていたくなかった').should_not be_causative 220 | end 221 | end 222 | 223 | describe Langue::Japanese::Verb, '#aggressive?' do 224 | it 'returns true if it is aggressive' do 225 | verb('話したい').should be_aggressive 226 | end 227 | 228 | it 'returns false if it is not aggressive' do 229 | verb('話されていなかった').should_not be_aggressive 230 | end 231 | end 232 | 233 | describe Langue::Japanese::Verb, '#negative?' do 234 | it 'returns true if it is negative' do 235 | verb('話さない').should be_negative 236 | verb('話さぬ').should be_negative 237 | verb('話しません').should be_negative 238 | verb('話すな').should be_negative 239 | end 240 | 241 | it 'returns false if it is not negative' do 242 | verb('話されていたかった').should_not be_negative 243 | verb('話したな').should_not be_negative 244 | verb('話さなくない').should_not be_negative 245 | end 246 | end 247 | 248 | describe Langue::Japanese::Verb, '#perfective?' do 249 | it 'returns true if it is perfective' do 250 | verb('話した').should be_perfective 251 | verb('去りぬ').should be_perfective 252 | end 253 | 254 | it 'returns false if it is not perfective' do 255 | verb('話されていたくない').should_not be_perfective 256 | end 257 | end 258 | 259 | describe Langue::Japanese::Verb, '#imperative?' do 260 | it 'returns true if it is imperative' do 261 | verb('話せ').should be_imperative 262 | verb('寝ろよ').should be_imperative 263 | verb('話してください').should be_imperative 264 | verb('話して').should be_imperative 265 | verb('話してよ').should be_imperative 266 | verb('話すな').should be_imperative 267 | end 268 | 269 | it 'returns false if it is not imperative' do 270 | verb('話されていたくなかった').should_not be_imperative 271 | verb('話したな').should_not be_imperative 272 | end 273 | end 274 | -------------------------------------------------------------------------------- /spec/langue/japanese/parser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'langue/japanese/parser' 3 | 4 | describe Langue::Japanese::Parser, '#initialize' do 5 | it 'sets an empty hash to tagger_options attribute by default' do 6 | parser = described_class.new 7 | tagger_options = parser.tagger_options 8 | tagger_options.should be_a(Hash) 9 | tagger_options.should be_empty 10 | end 11 | 12 | it 'sets an instance of Langue::Japanese::Logging::NullLogger to @logger by default' do 13 | parser = described_class.new 14 | logger = parser.instance_eval { @logger } 15 | logger.should be_a(Langue::Japanese::Logging::NullLogger) 16 | end 17 | 18 | it 'sets an empty hash to @taggers by default' do 19 | parser = described_class.new 20 | taggers = parser.instance_eval { @taggers } 21 | taggers.should be_a(Hash) 22 | taggers.should be_empty 23 | end 24 | 25 | context 'with tagger_options option' do 26 | it 'sets the value of tagger_options option to tagger_options attribute' do 27 | parser = described_class.new(:tagger_options => {:key => 'value'}) 28 | parser.tagger_options.should == {:key => 'value'} 29 | end 30 | end 31 | 32 | context 'with logger option' do 33 | it 'sets the value of logger option to @logger' do 34 | parser = described_class.new(:logger => 'logger') 35 | logger = parser.instance_eval { @logger } 36 | logger.should == 'logger' 37 | end 38 | end 39 | end 40 | 41 | describe Langue::Japanese::Parser, '#parse' do 42 | before do 43 | parser = described_class.new 44 | parser.stub!(:tagger).and_return(parser_tagger_stub(3)) 45 | @morphemes = parser.parse('text') 46 | end 47 | 48 | it 'returns an instance of Langue::Morphemes' do 49 | @morphemes.should be_a(Langue::Morphemes) 50 | end 51 | 52 | it 'returns an array with the number of morpheme' do 53 | @morphemes.should have(3).items 54 | end 55 | 56 | it 'returns an array containing the contents of the morpheme' do 57 | @morphemes[0].text.should == '1' 58 | @morphemes[1].text.should == '2' 59 | @morphemes[2].text.should == '3' 60 | end 61 | end 62 | 63 | describe Langue::Japanese::Parser, '#tagger' do 64 | before do 65 | @parser = described_class.new 66 | end 67 | 68 | def set_version(version) 69 | old_version = MeCab::VERSION 70 | 71 | MeCab.module_eval do 72 | remove_const(:VERSION) 73 | const_set(:VERSION, version) 74 | end 75 | 76 | return old_version unless block_given? 77 | 78 | begin 79 | yield 80 | ensure 81 | set_version(old_version) 82 | end 83 | end 84 | 85 | it 'returns an instance of MeCab::Tagger' do 86 | tagger = @parser.send(:tagger) 87 | tagger.should be_a(MeCab::Tagger) 88 | end 89 | 90 | it "calls tagger_with with tagger_options attribute if MeCab's version is 0.98" do 91 | set_version('0.98') do 92 | @parser.should_receive(:tagger_with).with('tagger_options') 93 | @parser.stub!(:tagger_options_as_string).and_return('tagger_options') 94 | @parser.send(:tagger) 95 | end 96 | end 97 | 98 | it "calls tagger_by_model_with with tagger_options attribute if MeCab's version is 0.99 later" do 99 | set_version('0.99') do 100 | @parser.should_receive(:tagger_by_model_with).with('tagger_options') 101 | @parser.stub!(:tagger_options_as_string).and_return('tagger_options') 102 | @parser.send(:tagger) 103 | end 104 | end 105 | end 106 | 107 | describe Langue::Japanese::Parser, '#tagger_with' do 108 | before do 109 | @parser = described_class.new 110 | end 111 | 112 | it 'calls MeCab::Tagger.new with tagger_options attribute' do 113 | MeCab::Tagger.should_receive(:new).with('tagger_options').and_return(parser_tagger_stub) 114 | @parser.send(:tagger_with, 'tagger_options') 115 | end 116 | 117 | it 'returns an instance of MeCab::Tagger' do 118 | tagger_stub = parser_tagger_stub 119 | tagger = @parser.send(:tagger_with, 'tagger_options') 120 | tagger.should == tagger_stub 121 | end 122 | end 123 | 124 | describe Langue::Japanese::Parser, '#tagger_by_model_with' do 125 | before do 126 | @parser = described_class.new 127 | @parser.instance_eval { @@models = {} } 128 | end 129 | 130 | it 'calls MeCab::Model.create with mecab_options attribute' do 131 | MeCab::Model.should_receive(:create).with('tagger_options').and_return(parser_model_stub) 132 | @parser.send(:tagger_by_model_with, 'tagger_options') 133 | end 134 | 135 | it 'calls MeCab::Model#createTagger' do 136 | parser_model_stub do |m| 137 | m.should_receive(:createTagger) 138 | end 139 | 140 | @parser.send(:tagger_by_model_with, 'tagger_options') 141 | end 142 | 143 | it 'returns an instance of MeCab::Tagger' do 144 | tagger_stub = parser_tagger_stub 145 | parser_model_stub(tagger_stub) 146 | tagger = @parser.send(:tagger_by_model_with, 'tagger_options') 147 | tagger.should == tagger_stub 148 | end 149 | end 150 | 151 | describe Langue::Japanese::Parser, '#tagger_options_as_string' do 152 | it 'returns an empty string if it does not give options' do 153 | parser = described_class.new 154 | tagger_options = parser.send(:tagger_options_as_string) 155 | tagger_options.should be_a(String) 156 | tagger_options.should be_empty 157 | end 158 | 159 | context 'with sysdic option' do 160 | it 'returns a string included d option' do 161 | parser = described_class.new(:tagger_options => {:sysdic => 'sysdic'}) 162 | parser.send(:tagger_options_as_string).should == '-d sysdic' 163 | end 164 | end 165 | 166 | context 'with userdic option' do 167 | it 'returns a string included u option' do 168 | parser = described_class.new(:tagger_options => {:userdic => 'userdic'}) 169 | parser.send(:tagger_options_as_string).should == '-u userdic' 170 | end 171 | end 172 | 173 | context 'with an unsupported option' do 174 | it 'logs that an option is unsupported' do 175 | parser = described_class.new(:tagger_options => {:unsupported => 'value'}) 176 | 177 | parser.instance_eval { @logger }.should_receive(:post).with('langue.japanese.parser', { 178 | :level => 'warn', 179 | :message => "'unsupported' option is unsupported", 180 | :key => :unsupported 181 | }) 182 | 183 | parser.send(:tagger_options_as_string) 184 | end 185 | end 186 | end 187 | 188 | describe Langue::Japanese::Parser, '#create_morpheme' do 189 | before do 190 | @parser = described_class.new 191 | end 192 | 193 | it 'returns an expected morpheme' do 194 | surface = 'surface' 195 | feature = 'part_of_speech,category1,category2,category3,inflection,inflection_type,root_form,yomi,pronunciation' 196 | morpheme = @parser.send(:create_morpheme, surface, feature) 197 | morpheme.text.should == 'surface' 198 | morpheme.part_of_speech.should == 'part_of_speech' 199 | morpheme.categories.should == %w(category1 category2 category3) 200 | morpheme.inflection.should == 'inflection' 201 | morpheme.inflection_type.should == 'inflection_type' 202 | morpheme.root_form.should == 'root_form' 203 | morpheme.yomi.should == 'yomi' 204 | morpheme.pronunciation.should == 'pronunciation' 205 | end 206 | 207 | it 'replaces to nil from the asterisk' do 208 | surface = 'surface' 209 | feature = '*,*,*,*,*,*,*,*,*' 210 | morpheme = @parser.send(:create_morpheme, surface, feature) 211 | morpheme.part_of_speech.should be_nil 212 | morpheme.categories.should be_empty 213 | morpheme.inflection.should be_nil 214 | morpheme.inflection_type.should be_nil 215 | morpheme.root_form.should be_nil 216 | morpheme.yomi.should be_nil 217 | morpheme.pronunciation.should be_nil 218 | end 219 | end 220 | -------------------------------------------------------------------------------- /lib/langue/japanese/inflector/default.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | Langue::Japanese::Inflector.inflections do 3 | adjective_forms = %w( 4 | 未然形 5 | 未然ウ接続 6 | 未然ヌ接続 7 | 連用タ接続 8 | 連用テ接続 9 | 連用ゴザイ接続 10 | 終止形 11 | 終止形-感動 12 | 連体形 13 | 体言接続 14 | 仮定形 15 | 仮定縮約1 16 | 仮定縮約2 17 | ガル接続 18 | ) 19 | 20 | category *adjective_forms do 21 | inflection '形容詞・アウオ段', 'い', { 22 | '未然形' => 'く', 23 | '未然ウ接続' => 'かろ', 24 | '未然ヌ接続' => 'から', 25 | '連用タ接続' => 'かっ', 26 | '連用テ接続' => 'く', 27 | '連用ゴザイ接続' => 'う', 28 | '終止形' => 'い', 29 | '終止形-感動' => '', 30 | '連体形' => 'い', 31 | '体言接続' => 'き', 32 | '仮定形' => 'けれ', 33 | '仮定縮約1' => 'けりゃ', 34 | '仮定縮約2' => 'きゃ', 35 | 'ガル接続' => '' 36 | } 37 | 38 | inflection '形容詞・イ段', 'い', { 39 | '未然形' => 'く', 40 | '未然ウ接続' => 'かろ', 41 | '未然ヌ接続' => 'から', 42 | '連用タ接続' => 'かっ', 43 | '連用テ接続' => 'く', 44 | '連用ゴザイ接続' => 'ゅう', 45 | '終止形' => 'い', 46 | '終止形-感動' => '', 47 | '連体形' => 'い', 48 | '体言接続' => 'き', 49 | '仮定形' => 'けれ', 50 | '仮定縮約1' => 'けりゃ', 51 | '仮定縮約2' => 'きゃ', 52 | 'ガル接続' => '' 53 | } 54 | 55 | inflection '形容動詞', '', { 56 | '未然形' => 'じゃ', 57 | '未然ウ接続' => lambda { |options| options[:desu] ? 'でしょ' : 'だろ' }, 58 | '未然ヌ接続' => 'なら', 59 | '連用タ接続' => lambda { |options| options[:desu] ? 'でし' : 'だっ' }, 60 | '連用テ接続' => lambda { |options| options[:desu] ? 'でし' : ['', true] }, 61 | '連用ゴザイ接続' => 'で', 62 | '終止形' => lambda { |options| options[:desu] ? 'です' : 'だ' }, 63 | '終止形-感動' => '', 64 | '連体形' => 'な', 65 | '体言接続' => 'な', 66 | '仮定形' => 'なら', 67 | '仮定縮約1' => 'なら', 68 | '仮定縮約2' => 'なら', 69 | 'ガル接続' => '' 70 | } 71 | end 72 | 73 | verb_forms = %w( 74 | 未然形 75 | 未然ウ接続 76 | 未然ヌ接続 77 | 未然レル接続 78 | 連用形 79 | 連用タ接続 80 | 終止形 81 | 仮定形 82 | 仮定縮約 83 | 命令形 84 | ) 85 | 86 | category *verb_forms do 87 | inflection '一段', 'る', { 88 | '未然形' => '', 89 | '未然ウ接続' => 'よ', 90 | '未然ヌ接続' => '', 91 | '未然レル接続' => '', 92 | '連用形' => '', 93 | '連用タ接続' => '', 94 | '終止形' => 'る', 95 | '仮定形' => 'れ', 96 | '仮定縮約' => 'りゃ', 97 | '命令形' => 'ろ' 98 | } 99 | 100 | inflection '一段・クレル', 'る', { 101 | '未然形' => '', 102 | '未然ウ接続' => 'よ', 103 | '未然ヌ接続' => '', 104 | '未然レル接続' => '', 105 | '連用形' => '', 106 | '連用タ接続' => '', 107 | '終止形' => 'る', 108 | '仮定形' => 'れ', 109 | '仮定縮約' => 'りゃ', 110 | '命令形' => '' 111 | } 112 | 113 | inflection '五段・カ行イ音便', 'く', { 114 | '未然形' => 'か', 115 | '未然ウ接続' => 'こ', 116 | '未然ヌ接続' => 'か', 117 | '未然レル接続' => 'か', 118 | '連用形' => 'き', 119 | '連用タ接続' => 'い', 120 | '終止形' => 'く', 121 | '仮定形' => 'け', 122 | '仮定縮約' => 'きゃ', 123 | '命令形' => 'け' 124 | } 125 | 126 | inflection '五段・カ行促音便', 'く', { 127 | '未然形' => 'か', 128 | '未然ウ接続' => 'こ', 129 | '未然ヌ接続' => 'か', 130 | '未然レル接続' => 'か', 131 | '連用形' => 'き', 132 | '連用タ接続' => 'っ', 133 | '終止形' => 'く', 134 | '仮定形' => 'け', 135 | '仮定縮約' => 'きゃ', 136 | '命令形' => 'け' 137 | } 138 | 139 | inflection '五段・カ行促音便ユク', 'く', { 140 | '未然形' => 'か', 141 | '未然ウ接続' => 'こ', 142 | '未然ヌ接続' => 'か', 143 | '未然レル接続' => 'か', 144 | '連用形' => 'き', 145 | '連用タ接続' => 'っ', 146 | '終止形' => 'く', 147 | '仮定形' => 'け', 148 | '仮定縮約' => 'きゃ', 149 | '命令形' => 'け' 150 | } 151 | 152 | inflection 'カ変・クル', 'くる', { 153 | '未然形' => 'こ', 154 | '未然ウ接続' => 'こよ', 155 | '未然ヌ接続' => 'こ', 156 | '未然レル接続' => 'こ', 157 | '連用形' => 'き', 158 | '連用タ接続' => 'き', 159 | '終止形' => 'くる', 160 | '仮定形' => 'くれ', 161 | '仮定縮約' => 'くりゃ', 162 | '命令形' => 'こい' 163 | } 164 | 165 | inflection 'カ変・来ル', 'る', { 166 | '未然形' => '', 167 | '未然ウ接続' => 'よ', 168 | '未然ヌ接続' => '', 169 | '未然レル接続' => '', 170 | '連用形' => '', 171 | '連用タ接続' => '', 172 | '終止形' => 'る', 173 | '仮定形' => 'れ', 174 | '仮定縮約' => 'りゃ', 175 | '命令形' => 'い' 176 | } 177 | 178 | inflection '五段・ガ行', 'ぐ', { 179 | '未然形' => 'が', 180 | '未然ウ接続' => 'ご', 181 | '未然ヌ接続' => 'が', 182 | '未然レル接続' => 'が', 183 | '連用形' => 'ぎ', 184 | '連用タ接続' => ['い', true], 185 | '終止形' => 'ぐ', 186 | '仮定形' => 'げ', 187 | '仮定縮約' => 'ぎゃ', 188 | '命令形' => 'げ' 189 | } 190 | 191 | inflection '五段・サ行', 'す', { 192 | '未然形' => 'さ', 193 | '未然ウ接続' => 'そ', 194 | '未然ヌ接続' => 'さ', 195 | '未然レル接続' => 'さ', 196 | '連用形' => 'し', 197 | '連用タ接続' => 'し', 198 | '終止形' => 'す', 199 | '仮定形' => 'せ', 200 | '仮定縮約' => 'しゃ', 201 | '命令形' => 'せ' 202 | } 203 | 204 | inflection '四段・サ行', 'す', { 205 | '未然形' => 'さ', 206 | '未然ウ接続' => 'そ', 207 | '未然ヌ接続' => 'さ', 208 | '未然レル接続' => 'さ', 209 | '連用形' => 'し', 210 | '連用タ接続' => 'し', 211 | '終止形' => 'す', 212 | '仮定形' => 'せ', 213 | '仮定縮約' => 'しゃ', 214 | '命令形' => 'せ' 215 | } 216 | 217 | inflection 'サ変・スル', 'する', { 218 | '未然形' => 'し', 219 | '未然ウ接続' => 'しよ', 220 | '未然ヌ接続' => 'せ', 221 | '未然レル接続' => 'さ', 222 | '連用形' => 'し', 223 | '連用タ接続' => 'し', 224 | '終止形' => 'する', 225 | '仮定形' => 'すれ', 226 | '仮定縮約' => 'すりゃ', 227 | '命令形' => 'しろ' 228 | } 229 | 230 | inflection 'サ変・−スル', 'する', { 231 | '未然形' => 'し', 232 | '未然ウ接続' => 'しよ', 233 | '未然ヌ接続' => 'し', 234 | '未然レル接続' => 'せ', 235 | '連用形' => 'し', 236 | '連用タ接続' => 'し', 237 | '終止形' => 'する', 238 | '仮定形' => 'すれ', 239 | '仮定縮約' => 'すりゃ', 240 | '命令形' => 'しろ' 241 | } 242 | 243 | inflection 'サ変・−ズル', 'ずる', { 244 | '未然形' => 'ぜ', 245 | '未然ウ接続' => 'ぜよ', 246 | '未然ヌ接続' => 'ぜ', 247 | '未然レル接続' => 'ぜ', 248 | '連用形' => 'じ', 249 | '連用タ接続' => 'じ', 250 | '終止形' => 'ずる', 251 | '仮定形' => 'ずれ', 252 | '仮定縮約' => 'ずりゃ', 253 | '命令形' => 'じろ' 254 | } 255 | 256 | inflection '五段・タ行', 'つ', { 257 | '未然形' => 'た', 258 | '未然ウ接続' => 'と', 259 | '未然ヌ接続' => 'た', 260 | '未然レル接続' => 'た', 261 | '連用形' => 'ち', 262 | '連用タ接続' => 'っ', 263 | '終止形' => 'つ', 264 | '仮定形' => 'て', 265 | '仮定縮約' => 'ちゃ', 266 | '命令形' => 'て' 267 | } 268 | 269 | inflection '四段・タ行', 'つ', { 270 | '未然形' => 'た', 271 | '未然ウ接続' => 'と', 272 | '未然ヌ接続' => 'た', 273 | '未然レル接続' => 'た', 274 | '連用形' => 'ち', 275 | '連用タ接続' => 'っ', 276 | '終止形' => 'つ', 277 | '仮定形' => 'て', 278 | '仮定縮約' => 'ちゃ', 279 | '命令形' => 'て' 280 | } 281 | 282 | inflection '五段・ナ行', 'ぬ', { 283 | '未然形' => 'な', 284 | '未然ウ接続' => 'の', 285 | '未然ヌ接続' => 'な', 286 | '未然レル接続' => 'な', 287 | '連用形' => 'に', 288 | '連用タ接続' => ['ん', true], 289 | '終止形' => 'ぬ', 290 | '仮定形' => 'ね', 291 | '仮定縮約' => 'にゃ', 292 | '命令形' => 'ね' 293 | } 294 | 295 | inflection '四段・ハ行', 'ふ', { 296 | '未然形' => 'は', 297 | '未然ウ接続' => 'ほ', 298 | '未然ヌ接続' => 'は', 299 | '未然レル接続' => 'は', 300 | '連用形' => 'ひ', 301 | '連用タ接続' => 'っ', 302 | '終止形' => 'ふ', 303 | '仮定形' => 'へ', 304 | '仮定縮約' => 'ひゃ', 305 | '命令形' => 'へ' 306 | } 307 | 308 | inflection '五段・バ行', 'ぶ', { 309 | '未然形' => 'ば', 310 | '未然ウ接続' => 'ぼ', 311 | '未然ヌ接続' => 'ば', 312 | '未然レル接続' => 'ば', 313 | '連用形' => 'び', 314 | '連用タ接続' => ['ん', true], 315 | '終止形' => 'ぶ', 316 | '仮定形' => 'べ', 317 | '仮定縮約' => 'びゃ', 318 | '命令形' => 'べ' 319 | } 320 | 321 | inflection '五段・マ行', 'む', { 322 | '未然形' => 'ま', 323 | '未然ウ接続' => 'も', 324 | '未然ヌ接続' => 'ま', 325 | '未然レル接続' => 'ま', 326 | '連用形' => 'み', 327 | '連用タ接続' => ['ん', true], 328 | '終止形' => 'む', 329 | '仮定形' => 'め', 330 | '仮定縮約' => 'みゃ', 331 | '命令形' => 'め' 332 | } 333 | 334 | inflection '五段・ラ行', 'る', { 335 | '未然形' => 'ら', 336 | '未然ウ接続' => 'ろ', 337 | '未然ヌ接続' => 'ら', 338 | '未然レル接続' => 'ら', 339 | '連用形' => 'り', 340 | '連用タ接続' => 'っ', 341 | '終止形' => 'る', 342 | '仮定形' => 'れ', 343 | '仮定縮約' => 'りゃ', 344 | '命令形' => 'れ' 345 | } 346 | 347 | inflection '五段・ラ行特殊', 'る', { 348 | '未然形' => 'ら', 349 | '未然ウ接続' => 'ろ', 350 | '未然ヌ接続' => 'ら', 351 | '未然レル接続' => 'ら', 352 | '連用形' => 'い', 353 | '連用タ接続' => 'っ', 354 | '終止形' => 'る', 355 | '仮定形' => 'れ', 356 | '仮定縮約' => 'りゃ', 357 | '命令形' => 'い' 358 | } 359 | 360 | inflection '五段・ワ行ウ音便', 'う', { 361 | '未然形' => 'わ', 362 | '未然ウ接続' => 'お', 363 | '未然ヌ接続' => 'わ', 364 | '未然レル接続' => 'わ', 365 | '連用形' => 'い', 366 | '連用タ接続' => 'う', 367 | '終止形' => 'う', 368 | '仮定形' => 'え', 369 | '仮定縮約' => 'や', 370 | '命令形' => 'え' 371 | } 372 | 373 | inflection '五段・ワ行促音便', 'う', { 374 | '未然形' => 'わ', 375 | '未然ウ接続' => 'お', 376 | '未然ヌ接続' => 'わ', 377 | '未然レル接続' => 'わ', 378 | '連用形' => 'い', 379 | '連用タ接続' => 'っ', 380 | '終止形' => 'う', 381 | '仮定形' => 'え', 382 | '仮定縮約' => 'や', 383 | '命令形' => 'え' 384 | } 385 | end 386 | 387 | auxiliary_verb_forms = %w() 388 | 389 | category *auxiliary_verb_forms do 390 | end 391 | 392 | inflection '特殊・ナイ', 'ない', { 393 | '未然ウ接続' => 'なかろ', 394 | '未然ヌ接続' => 'なから', 395 | '連用タ接続' => 'なかっ', 396 | '連用テ接続' => 'なく', 397 | '連用デ接続' => 'ない', 398 | '連用ゴザイ接続' => 'のう', 399 | '終止形' => 'ない', 400 | '音便終止形' => 'ねえ', 401 | '体言接続' => 'なき', 402 | '仮定形' => 'なけれ', 403 | '仮定縮約1' => 'なけりゃ', 404 | '仮定縮約2' => 'なきゃ', 405 | 'ガル接続' => 'な', 406 | '命令形' => 'なかれ' 407 | } 408 | 409 | inflection '特殊・タイ', 'たい', { 410 | '未然ウ接続' => 'たかろ', 411 | '未然ヌ接続' => 'たから', 412 | '連用タ接続' => 'たかっ', 413 | '連用テ接続' => 'たく', 414 | '連用ゴザイ接続' => 'とう', 415 | '終止形' => 'たい', 416 | '音便終止形' => 'てえ', 417 | '体言接続' => 'たき', 418 | '仮定形' => 'たけれ', 419 | '仮定縮約1' => 'たけりゃ', 420 | '仮定縮約2' => 'たきゃ', 421 | 'ガル接続' => 'た' 422 | } 423 | 424 | inflection '特殊・デス', 'す', { 425 | '未然形' => 'しょ', 426 | '連用形' => 'し', 427 | '終止形' => 'す' 428 | } 429 | 430 | inflection '特殊・マス', 'す', { 431 | '終止形' => 'す', 432 | '未然形' => 'せ', 433 | '未然ウ接続' => 'しょ', 434 | '連用形' => 'し', 435 | '仮定形' => 'すれ', 436 | '命令形' => 'せ' 437 | } 438 | 439 | inflection '特殊・タ', '', { 440 | '未然形' => 'ろ', 441 | '終止形' => '', 442 | '仮定形' => 'ら' 443 | } 444 | 445 | inflection '特殊・ダ', 'だ', { 446 | '未然形' => 'だろ', 447 | '連用形' => 'で', 448 | '連用タ接続' => 'だっ', 449 | '終止形' => 'だ', 450 | '体言接続' => 'な', 451 | '仮定形' => 'なら', 452 | '命令形' => 'なれ' 453 | } 454 | end 455 | -------------------------------------------------------------------------------- /spec/langue/japanese/inflector_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'langue/japanese/inflector' 3 | 4 | describe Langue::Japanese::Inflector, '#initialize' do 5 | it 'sets an instance of Langue::Japanese::Logging::NullLogger to @logger' do 6 | inflector = described_class.new 7 | logger = inflector.instance_variable_get(:@logger) 8 | logger.should be_a(Langue::Japanese::Logging::NullLogger) 9 | end 10 | 11 | context 'with :logger option' do 12 | it 'sets the value of :logger option to @logger' do 13 | inflector = described_class.new(:logger => 'logger') 14 | logger = inflector.instance_variable_get(:@logger) 15 | logger.should == 'logger' 16 | end 17 | end 18 | end 19 | 20 | describe Langue::Japanese::Inflector, '#inflect' do 21 | before do 22 | @inflector = described_class.new 23 | end 24 | 25 | it 'calls #inflect of the inflection with the word, with inflectional form and the options' do 26 | inflection = mock.tap do |m| 27 | m.should_receive(:inflect).with('word', 'form', :key => 'value') 28 | end 29 | 30 | described_class.inflections.stub!(:[]).with('classification').and_return(inflection) 31 | @inflector.inflect('classification', 'word', 'form', :key => 'value') 32 | end 33 | 34 | it 'raises ArgumentError if the inflectional classification does not exist' do 35 | lambda { @inflector.inflect('classification', 'word', 'form') }.should raise_error(ArgumentError, '"classification" inflection does not exist') 36 | end 37 | 38 | context 'with an adjective' do 39 | context 'with 形容詞・アウオ段' do 40 | before do 41 | @inflection_name = '形容詞・アウオ段' 42 | @word = '賢い' 43 | end 44 | 45 | it 'inflects to 未然形' do 46 | @inflector.inflect(@inflection_name, @word, '未然形').should == '賢く' 47 | end 48 | 49 | it 'inflects to 未然ウ接続' do 50 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '賢かろ' 51 | end 52 | 53 | it 'inflects to 未然ヌ接続' do 54 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '賢から' 55 | end 56 | 57 | it 'inflects to 連用タ接続' do 58 | @inflector.inflect(@inflection_name, @word, '連用タ接続').should == '賢かっ' 59 | end 60 | 61 | it 'inflects to 連用テ接続' do 62 | @inflector.inflect(@inflection_name, @word, '連用テ接続', :following => 'て').should == '賢くて' 63 | end 64 | 65 | it 'inflects to 連用ゴザイ接続' do 66 | @inflector.inflect(@inflection_name, @word, '連用ゴザイ接続').should == '賢う' 67 | end 68 | 69 | it 'inflects to 終止形' do 70 | @inflector.inflect(@inflection_name, @word, '終止形').should == '賢い' 71 | end 72 | 73 | it 'inflects to 終止形-感動' do 74 | @inflector.inflect(@inflection_name, @word, '終止形-感動').should == '賢' 75 | end 76 | 77 | it 'inflects to 連体形' do 78 | @inflector.inflect(@inflection_name, @word, '連体形').should == '賢い' 79 | end 80 | 81 | it 'inflects to 体言接続' do 82 | @inflector.inflect(@inflection_name, @word, '体言接続').should == '賢き' 83 | end 84 | 85 | it 'inflects to 仮定形' do 86 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '賢けれ' 87 | end 88 | 89 | it 'inflects to 仮定縮約1' do 90 | @inflector.inflect(@inflection_name, @word, '仮定縮約1').should == '賢けりゃ' 91 | end 92 | 93 | it 'inflects to 仮定縮約2' do 94 | @inflector.inflect(@inflection_name, @word, '仮定縮約2').should == '賢きゃ' 95 | end 96 | 97 | it 'inflects to ガル接続' do 98 | @inflector.inflect(@inflection_name, @word, 'ガル接続').should == '賢' 99 | end 100 | end 101 | 102 | context 'with 形容詞・イ段' do 103 | before do 104 | @inflection_name = '形容詞・イ段' 105 | @word = '楽しい' 106 | end 107 | 108 | it 'inflects to 未然形' do 109 | @inflector.inflect(@inflection_name, @word, '未然形').should == '楽しく' 110 | end 111 | 112 | it 'inflects to 未然ウ接続' do 113 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '楽しかろ' 114 | end 115 | 116 | it 'inflects to 未然ヌ接続' do 117 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '楽しから' 118 | end 119 | 120 | it 'inflects to 連用タ接続' do 121 | @inflector.inflect(@inflection_name, @word, '連用タ接続').should == '楽しかっ' 122 | end 123 | 124 | it 'inflects to 連用テ接続' do 125 | @inflector.inflect(@inflection_name, @word, '連用テ接続', :following => 'て').should == '楽しくて' 126 | end 127 | 128 | it 'inflects to 連用ゴザイ接続' do 129 | @inflector.inflect(@inflection_name, @word, '連用ゴザイ接続').should == '楽しゅう' 130 | end 131 | 132 | it 'inflects to 終止形' do 133 | @inflector.inflect(@inflection_name, @word, '終止形').should == '楽しい' 134 | end 135 | 136 | it 'inflects to 終止形-感動' do 137 | @inflector.inflect(@inflection_name, @word, '終止形-感動').should == '楽し' 138 | end 139 | 140 | it 'inflects to 連体形' do 141 | @inflector.inflect(@inflection_name, @word, '連体形').should == '楽しい' 142 | end 143 | 144 | it 'inflects to 体言接続' do 145 | @inflector.inflect(@inflection_name, @word, '体言接続').should == '楽しき' 146 | end 147 | 148 | it 'inflects to 仮定形' do 149 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '楽しけれ' 150 | end 151 | 152 | it 'inflects to 仮定縮約1' do 153 | @inflector.inflect(@inflection_name, @word, '仮定縮約1').should == '楽しけりゃ' 154 | end 155 | 156 | it 'inflects to 仮定縮約2' do 157 | @inflector.inflect(@inflection_name, @word, '仮定縮約2').should == '楽しきゃ' 158 | end 159 | 160 | it 'inflects to ガル接続' do 161 | @inflector.inflect(@inflection_name, @word, 'ガル接続').should == '楽し' 162 | end 163 | end 164 | end 165 | 166 | context 'with an adjectival noun' do 167 | before do 168 | @inflection_name = '形容動詞' 169 | @word = '静か' 170 | end 171 | 172 | it 'inflects to 未然形' do 173 | @inflector.inflect(@inflection_name, @word, '未然形').should == '静かじゃ' 174 | end 175 | 176 | it 'inflects to 未然ウ接続' do 177 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '静かだろ' 178 | end 179 | 180 | it 'inflects to 未然ヌ接続' do 181 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '静かなら' 182 | end 183 | 184 | it 'inflects to 連用タ接続' do 185 | @inflector.inflect(@inflection_name, @word, '連用タ接続').should == '静かだっ' 186 | end 187 | 188 | it 'inflects to 連用テ接続' do 189 | @inflector.inflect(@inflection_name, @word, '連用テ接続', :following => 'て').should == '静かで' 190 | end 191 | 192 | it 'inflects to 連用ゴザイ接続' do 193 | @inflector.inflect(@inflection_name, @word, '連用ゴザイ接続').should == '静かで' 194 | end 195 | 196 | it 'inflects to 終止形' do 197 | @inflector.inflect(@inflection_name, @word, '終止形').should == '静かだ' 198 | end 199 | 200 | it 'inflects to 終止形-感動' do 201 | @inflector.inflect(@inflection_name, @word, '終止形-感動').should == '静か' 202 | end 203 | 204 | it 'inflects to 連体形' do 205 | @inflector.inflect(@inflection_name, @word, '連体形').should == '静かな' 206 | end 207 | 208 | it 'inflects to 体言接続' do 209 | @inflector.inflect(@inflection_name, @word, '体言接続').should == '静かな' 210 | end 211 | 212 | it 'inflects to 仮定形' do 213 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '静かなら' 214 | end 215 | 216 | it 'inflects to 仮定縮約1' do 217 | @inflector.inflect(@inflection_name, @word, '仮定縮約1').should == '静かなら' 218 | end 219 | 220 | it 'inflects to 仮定縮約2' do 221 | @inflector.inflect(@inflection_name, @word, '仮定縮約2').should == '静かなら' 222 | end 223 | 224 | it 'inflects to ガル接続' do 225 | @inflector.inflect(@inflection_name, @word, 'ガル接続').should == '静か' 226 | end 227 | 228 | context 'with :desu option' do 229 | it 'inflects to 未然ウ接続' do 230 | @inflector.inflect(@inflection_name, @word, '未然ウ接続', :desu => true).should == '静かでしょ' 231 | end 232 | 233 | it 'inflects to 連用タ接続' do 234 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :desu => true).should == '静かでし' 235 | end 236 | 237 | it 'inflects to 連用テ接続' do 238 | @inflector.inflect(@inflection_name, @word, '連用テ接続', :following => 'て', :desu => true).should == '静かでして' 239 | end 240 | 241 | it 'inflects to 終止形' do 242 | @inflector.inflect(@inflection_name, @word, '終止形', :desu => true).should == '静かです' 243 | end 244 | end 245 | end 246 | 247 | context 'with a verb' do 248 | context 'with 一段' do 249 | before do 250 | @inflection_name = '一段' 251 | @word = '食べる' 252 | end 253 | 254 | it 'inflects to 未然形' do 255 | @inflector.inflect(@inflection_name, @word, '未然形').should == '食べ' 256 | end 257 | 258 | it 'inflects to 未然ウ接続' do 259 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '食べよ' 260 | end 261 | 262 | it 'inflects to 未然ヌ接続' do 263 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '食べ' 264 | end 265 | 266 | it 'inflects to 未然レル接続' do 267 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '食べ' 268 | end 269 | 270 | it 'inflects to 連用形' do 271 | @inflector.inflect(@inflection_name, @word, '連用形').should == '食べ' 272 | end 273 | 274 | it 'inflects to 連用タ接続' do 275 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '食べた' 276 | end 277 | 278 | it 'inflects to 終止形' do 279 | @inflector.inflect(@inflection_name, @word, '終止形').should == '食べる' 280 | end 281 | 282 | it 'inflects to 仮定形' do 283 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '食べれ' 284 | end 285 | 286 | it 'inflects to 仮定縮約' do 287 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '食べりゃ' 288 | end 289 | 290 | it 'inflects to 命令形' do 291 | @inflector.inflect(@inflection_name, @word, '命令形').should == '食べろ' 292 | end 293 | end 294 | 295 | context 'with 一段・クレル' do 296 | before do 297 | @inflection_name = '一段・クレル' 298 | @word = '呉れる' 299 | end 300 | 301 | it 'inflects to 未然形' do 302 | @inflector.inflect(@inflection_name, @word, '未然形').should == '呉れ' 303 | end 304 | 305 | it 'inflects to 未然ウ接続' do 306 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '呉れよ' 307 | end 308 | 309 | it 'inflects to 未然ヌ接続' do 310 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '呉れ' 311 | end 312 | 313 | it 'inflects to 未然レル接続' do 314 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '呉れ' 315 | end 316 | 317 | it 'inflects to 連用形' do 318 | @inflector.inflect(@inflection_name, @word, '連用形').should == '呉れ' 319 | end 320 | 321 | it 'inflects to 連用タ接続' do 322 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '呉れた' 323 | end 324 | 325 | it 'inflects to 終止形' do 326 | @inflector.inflect(@inflection_name, @word, '終止形').should == '呉れる' 327 | end 328 | 329 | it 'inflects to 仮定形' do 330 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '呉れれ' 331 | end 332 | 333 | it 'inflects to 仮定縮約' do 334 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '呉れりゃ' 335 | end 336 | 337 | it 'inflects to 命令形' do 338 | @inflector.inflect(@inflection_name, @word, '命令形').should == '呉れ' 339 | end 340 | end 341 | 342 | context 'with 五段・カ行イ音便' do 343 | before do 344 | @inflection_name = '五段・カ行イ音便' 345 | @word = '書く' 346 | end 347 | 348 | it 'inflects to 未然形' do 349 | @inflector.inflect(@inflection_name, @word, '未然形').should == '書か' 350 | end 351 | 352 | it 'inflects to 未然ウ接続' do 353 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '書こ' 354 | end 355 | 356 | it 'inflects to 未然ヌ接続' do 357 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '書か' 358 | end 359 | 360 | it 'inflects to 未然レル接続' do 361 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '書か' 362 | end 363 | 364 | it 'inflects to 連用形' do 365 | @inflector.inflect(@inflection_name, @word, '連用形').should == '書き' 366 | end 367 | 368 | it 'inflects to 連用タ接続' do 369 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '書いた' 370 | end 371 | 372 | it 'inflects to 終止形' do 373 | @inflector.inflect(@inflection_name, @word, '終止形').should == '書く' 374 | end 375 | 376 | it 'inflects to 仮定形' do 377 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '書け' 378 | end 379 | 380 | it 'inflects to 仮定縮約' do 381 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '書きゃ' 382 | end 383 | 384 | it 'inflects to 命令形' do 385 | @inflector.inflect(@inflection_name, @word, '命令形').should == '書け' 386 | end 387 | end 388 | 389 | context 'with 五段・カ行促音便' do 390 | before do 391 | @inflection_name = '五段・カ行促音便' 392 | @word = '付いて行く' 393 | end 394 | 395 | it 'inflects to 未然形' do 396 | @inflector.inflect(@inflection_name, @word, '未然形').should == '付いて行か' 397 | end 398 | 399 | it 'inflects to 未然ウ接続' do 400 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '付いて行こ' 401 | end 402 | 403 | it 'inflects to 未然ヌ接続' do 404 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '付いて行か' 405 | end 406 | 407 | it 'inflects to 未然レル接続' do 408 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '付いて行か' 409 | end 410 | 411 | it 'inflects to 連用形' do 412 | @inflector.inflect(@inflection_name, @word, '連用形').should == '付いて行き' 413 | end 414 | 415 | it 'inflects to 連用タ接続' do 416 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '付いて行った' 417 | end 418 | 419 | it 'inflects to 終止形' do 420 | @inflector.inflect(@inflection_name, @word, '終止形').should == '付いて行く' 421 | end 422 | 423 | it 'inflects to 仮定形' do 424 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '付いて行け' 425 | end 426 | 427 | it 'inflects to 仮定縮約' do 428 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '付いて行きゃ' 429 | end 430 | 431 | it 'inflects to 命令形' do 432 | @inflector.inflect(@inflection_name, @word, '命令形').should == '付いて行け' 433 | end 434 | end 435 | 436 | context 'with 五段・カ行促音便ユク' do 437 | before do 438 | @inflection_name = '五段・カ行促音便ユク' 439 | @word = '心行く' 440 | end 441 | 442 | it 'inflects to 未然形' do 443 | @inflector.inflect(@inflection_name, @word, '未然形').should == '心行か' 444 | end 445 | 446 | it 'inflects to 未然ウ接続' do 447 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '心行こ' 448 | end 449 | 450 | it 'inflects to 未然ヌ接続' do 451 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '心行か' 452 | end 453 | 454 | it 'inflects to 未然レル接続' do 455 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '心行か' 456 | end 457 | 458 | it 'inflects to 連用形' do 459 | @inflector.inflect(@inflection_name, @word, '連用形').should == '心行き' 460 | end 461 | 462 | it 'inflects to 連用タ接続' do 463 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '心行った' 464 | end 465 | 466 | it 'inflects to 終止形' do 467 | @inflector.inflect(@inflection_name, @word, '終止形').should == '心行く' 468 | end 469 | 470 | it 'inflects to 仮定形' do 471 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '心行け' 472 | end 473 | 474 | it 'inflects to 仮定縮約' do 475 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '心行きゃ' 476 | end 477 | 478 | it 'inflects to 命令形' do 479 | @inflector.inflect(@inflection_name, @word, '命令形').should == '心行け' 480 | end 481 | end 482 | 483 | context 'with カ変・クル' do 484 | before do 485 | @inflection_name = 'カ変・クル' 486 | @word = 'くる' 487 | end 488 | 489 | it 'inflects to 未然形' do 490 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'こ' 491 | end 492 | 493 | it 'inflects to 未然ウ接続' do 494 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == 'こよ' 495 | end 496 | 497 | it 'inflects to 未然ヌ接続' do 498 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == 'こ' 499 | end 500 | 501 | it 'inflects to 未然レル接続' do 502 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == 'こ' 503 | end 504 | 505 | it 'inflects to 連用形' do 506 | @inflector.inflect(@inflection_name, @word, '連用形').should == 'き' 507 | end 508 | 509 | it 'inflects to 連用タ接続' do 510 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == 'きた' 511 | end 512 | 513 | it 'inflects to 終止形' do 514 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'くる' 515 | end 516 | 517 | it 'inflects to 仮定形' do 518 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'くれ' 519 | end 520 | 521 | it 'inflects to 仮定縮約' do 522 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == 'くりゃ' 523 | end 524 | 525 | it 'inflects to 命令形' do 526 | @inflector.inflect(@inflection_name, @word, '命令形').should == 'こい' 527 | end 528 | end 529 | 530 | context 'with カ変・来ル' do 531 | before do 532 | @inflection_name = 'カ変・来ル' 533 | @word = '来る' 534 | end 535 | 536 | it 'inflects to 未然形' do 537 | @inflector.inflect(@inflection_name, @word, '未然形').should == '来' 538 | end 539 | 540 | it 'inflects to 未然ウ接続' do 541 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '来よ' 542 | end 543 | 544 | it 'inflects to 未然ヌ接続' do 545 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '来' 546 | end 547 | 548 | it 'inflects to 未然レル接続' do 549 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '来' 550 | end 551 | 552 | it 'inflects to 連用形' do 553 | @inflector.inflect(@inflection_name, @word, '連用形').should == '来' 554 | end 555 | 556 | it 'inflects to 連用タ接続' do 557 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '来た' 558 | end 559 | 560 | it 'inflects to 終止形' do 561 | @inflector.inflect(@inflection_name, @word, '終止形').should == '来る' 562 | end 563 | 564 | it 'inflects to 仮定形' do 565 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '来れ' 566 | end 567 | 568 | it 'inflects to 仮定縮約' do 569 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '来りゃ' 570 | end 571 | 572 | it 'inflects to 命令形' do 573 | @inflector.inflect(@inflection_name, @word, '命令形').should == '来い' 574 | end 575 | end 576 | 577 | context 'with 五段・ガ行' do 578 | before do 579 | @inflection_name = '五段・ガ行' 580 | @word = '仰ぐ' 581 | end 582 | 583 | it 'inflects to 未然形' do 584 | @inflector.inflect(@inflection_name, @word, '未然形').should == '仰が' 585 | end 586 | 587 | it 'inflects to 未然ウ接続' do 588 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '仰ご' 589 | end 590 | 591 | it 'inflects to 未然ヌ接続' do 592 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '仰が' 593 | end 594 | 595 | it 'inflects to 未然レル接続' do 596 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '仰が' 597 | end 598 | 599 | it 'inflects to 連用形' do 600 | @inflector.inflect(@inflection_name, @word, '連用形').should == '仰ぎ' 601 | end 602 | 603 | it 'inflects to 連用タ接続' do 604 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '仰いだ' 605 | end 606 | 607 | it 'inflects to 終止形' do 608 | @inflector.inflect(@inflection_name, @word, '終止形').should == '仰ぐ' 609 | end 610 | 611 | it 'inflects to 仮定形' do 612 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '仰げ' 613 | end 614 | 615 | it 'inflects to 仮定縮約' do 616 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '仰ぎゃ' 617 | end 618 | 619 | it 'inflects to 命令形' do 620 | @inflector.inflect(@inflection_name, @word, '命令形').should == '仰げ' 621 | end 622 | end 623 | 624 | context 'with 五段・サ行' do 625 | before do 626 | @inflection_name = '五段・サ行' 627 | @word = '話す' 628 | end 629 | 630 | it 'inflects to 未然形' do 631 | @inflector.inflect(@inflection_name, @word, '未然形').should == '話さ' 632 | end 633 | 634 | it 'inflects to 未然ウ接続' do 635 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '話そ' 636 | end 637 | 638 | it 'inflects to 未然ヌ接続' do 639 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '話さ' 640 | end 641 | 642 | it 'inflects to 未然レル接続' do 643 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '話さ' 644 | end 645 | 646 | it 'inflects to 連用形' do 647 | @inflector.inflect(@inflection_name, @word, '連用形').should == '話し' 648 | end 649 | 650 | it 'inflects to 連用タ接続' do 651 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '話した' 652 | end 653 | 654 | it 'inflects to 終止形' do 655 | @inflector.inflect(@inflection_name, @word, '終止形').should == '話す' 656 | end 657 | 658 | it 'inflects to 仮定形' do 659 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '話せ' 660 | end 661 | 662 | it 'inflects to 仮定縮約' do 663 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '話しゃ' 664 | end 665 | 666 | it 'inflects to 命令形' do 667 | @inflector.inflect(@inflection_name, @word, '命令形').should == '話せ' 668 | end 669 | end 670 | 671 | context 'with 四段・サ行' do 672 | before do 673 | @inflection_name = '四段・サ行' 674 | @word = '天照らす' 675 | end 676 | 677 | it 'inflects to 未然形' do 678 | @inflector.inflect(@inflection_name, @word, '未然形').should == '天照らさ' 679 | end 680 | 681 | it 'inflects to 未然ウ接続' do 682 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '天照らそ' 683 | end 684 | 685 | it 'inflects to 未然ヌ接続' do 686 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '天照らさ' 687 | end 688 | 689 | it 'inflects to 未然レル接続' do 690 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '天照らさ' 691 | end 692 | 693 | it 'inflects to 連用形' do 694 | @inflector.inflect(@inflection_name, @word, '連用形').should == '天照らし' 695 | end 696 | 697 | it 'inflects to 連用タ接続' do 698 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '天照らした' 699 | end 700 | 701 | it 'inflects to 終止形' do 702 | @inflector.inflect(@inflection_name, @word, '終止形').should == '天照らす' 703 | end 704 | 705 | it 'inflects to 仮定形' do 706 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '天照らせ' 707 | end 708 | 709 | it 'inflects to 仮定縮約' do 710 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '天照らしゃ' 711 | end 712 | 713 | it 'inflects to 命令形' do 714 | @inflector.inflect(@inflection_name, @word, '命令形').should == '天照らせ' 715 | end 716 | end 717 | 718 | context 'with サ変・スル' do 719 | before do 720 | @inflection_name = 'サ変・スル' 721 | @word = 'する' 722 | end 723 | 724 | it 'inflects to 未然形' do 725 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'し' 726 | end 727 | 728 | it 'inflects to 未然ウ接続' do 729 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == 'しよ' 730 | end 731 | 732 | it 'inflects to 未然ヌ接続' do 733 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == 'せ' 734 | end 735 | 736 | it 'inflects to 未然レル接続' do 737 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == 'さ' 738 | end 739 | 740 | it 'inflects to 連用形' do 741 | @inflector.inflect(@inflection_name, @word, '連用形').should == 'し' 742 | end 743 | 744 | it 'inflects to 連用タ接続' do 745 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == 'した' 746 | end 747 | 748 | it 'inflects to 終止形' do 749 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'する' 750 | end 751 | 752 | it 'inflects to 仮定形' do 753 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'すれ' 754 | end 755 | 756 | it 'inflects to 仮定縮約' do 757 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == 'すりゃ' 758 | end 759 | 760 | it 'inflects to 命令形' do 761 | @inflector.inflect(@inflection_name, @word, '命令形').should == 'しろ' 762 | end 763 | end 764 | 765 | context 'with サ変・−スル' do 766 | before do 767 | @inflection_name = 'サ変・−スル' 768 | @word = '発する' 769 | end 770 | 771 | it 'inflects to 未然形' do 772 | @inflector.inflect(@inflection_name, @word, '未然形').should == '発し' 773 | end 774 | 775 | it 'inflects to 未然ウ接続' do 776 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '発しよ' 777 | end 778 | 779 | it 'inflects to 未然ヌ接続' do 780 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '発し' 781 | end 782 | 783 | it 'inflects to 未然レル接続' do 784 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '発せ' 785 | end 786 | 787 | it 'inflects to 連用形' do 788 | @inflector.inflect(@inflection_name, @word, '連用形').should == '発し' 789 | end 790 | 791 | it 'inflects to 連用タ接続' do 792 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '発した' 793 | end 794 | 795 | it 'inflects to 終止形' do 796 | @inflector.inflect(@inflection_name, @word, '終止形').should == '発する' 797 | end 798 | 799 | it 'inflects to 仮定形' do 800 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '発すれ' 801 | end 802 | 803 | it 'inflects to 仮定縮約' do 804 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '発すりゃ' 805 | end 806 | 807 | it 'inflects to 命令形' do 808 | @inflector.inflect(@inflection_name, @word, '命令形').should == '発しろ' 809 | end 810 | end 811 | 812 | context 'with サ変・−ズル' do 813 | before do 814 | @inflection_name = 'サ変・−ズル' 815 | @word = '存ずる' 816 | end 817 | 818 | it 'inflects to 未然形' do 819 | @inflector.inflect(@inflection_name, @word, '未然形').should == '存ぜ' 820 | end 821 | 822 | it 'inflects to 未然ウ接続' do 823 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '存ぜよ' 824 | end 825 | 826 | it 'inflects to 未然ヌ接続' do 827 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '存ぜ' 828 | end 829 | 830 | it 'inflects to 未然レル接続' do 831 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '存ぜ' 832 | end 833 | 834 | it 'inflects to 連用形' do 835 | @inflector.inflect(@inflection_name, @word, '連用形').should == '存じ' 836 | end 837 | 838 | it 'inflects to 連用タ接続' do 839 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '存じた' 840 | end 841 | 842 | it 'inflects to 終止形' do 843 | @inflector.inflect(@inflection_name, @word, '終止形').should == '存ずる' 844 | end 845 | 846 | it 'inflects to 仮定形' do 847 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '存ずれ' 848 | end 849 | 850 | it 'inflects to 仮定縮約' do 851 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '存ずりゃ' 852 | end 853 | 854 | it 'inflects to 命令形' do 855 | @inflector.inflect(@inflection_name, @word, '命令形').should == '存じろ' 856 | end 857 | end 858 | 859 | context 'with 五段・タ行' do 860 | before do 861 | @inflection_name = '五段・タ行' 862 | @word = '持つ' 863 | end 864 | 865 | it 'inflects to 未然形' do 866 | @inflector.inflect(@inflection_name, @word, '未然形').should == '持た' 867 | end 868 | 869 | it 'inflects to 未然ウ接続' do 870 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '持と' 871 | end 872 | 873 | it 'inflects to 未然ヌ接続' do 874 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '持た' 875 | end 876 | 877 | it 'inflects to 未然レル接続' do 878 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '持た' 879 | end 880 | 881 | it 'inflects to 連用形' do 882 | @inflector.inflect(@inflection_name, @word, '連用形').should == '持ち' 883 | end 884 | 885 | it 'inflects to 連用タ接続' do 886 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '持った' 887 | end 888 | 889 | it 'inflects to 終止形' do 890 | @inflector.inflect(@inflection_name, @word, '終止形').should == '持つ' 891 | end 892 | 893 | it 'inflects to 仮定形' do 894 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '持て' 895 | end 896 | 897 | it 'inflects to 仮定縮約' do 898 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '持ちゃ' 899 | end 900 | 901 | it 'inflects to 命令形' do 902 | @inflector.inflect(@inflection_name, @word, '命令形').should == '持て' 903 | end 904 | end 905 | 906 | context 'with 四段・タ行' do 907 | before do 908 | @inflection_name = '四段・タ行' 909 | @word = '群立つ' 910 | end 911 | 912 | it 'inflects to 未然形' do 913 | @inflector.inflect(@inflection_name, @word, '未然形').should == '群立た' 914 | end 915 | 916 | it 'inflects to 未然ウ接続' do 917 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '群立と' 918 | end 919 | 920 | it 'inflects to 未然ヌ接続' do 921 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '群立た' 922 | end 923 | 924 | it 'inflects to 未然レル接続' do 925 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '群立た' 926 | end 927 | 928 | it 'inflects to 連用形' do 929 | @inflector.inflect(@inflection_name, @word, '連用形').should == '群立ち' 930 | end 931 | 932 | it 'inflects to 連用タ接続' do 933 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '群立った' 934 | end 935 | 936 | it 'inflects to 終止形' do 937 | @inflector.inflect(@inflection_name, @word, '終止形').should == '群立つ' 938 | end 939 | 940 | it 'inflects to 仮定形' do 941 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '群立て' 942 | end 943 | 944 | it 'inflects to 仮定縮約' do 945 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '群立ちゃ' 946 | end 947 | 948 | it 'inflects to 命令形' do 949 | @inflector.inflect(@inflection_name, @word, '命令形').should == '群立て' 950 | end 951 | end 952 | 953 | context 'with 五段・ナ行' do 954 | before do 955 | @inflection_name = '五段・ナ行' 956 | @word = '死ぬ' 957 | end 958 | 959 | it 'inflects to 未然形' do 960 | @inflector.inflect(@inflection_name, @word, '未然形').should == '死な' 961 | end 962 | 963 | it 'inflects to 未然ウ接続' do 964 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '死の' 965 | end 966 | 967 | it 'inflects to 未然ヌ接続' do 968 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '死な' 969 | end 970 | 971 | it 'inflects to 未然レル接続' do 972 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '死な' 973 | end 974 | 975 | it 'inflects to 連用形' do 976 | @inflector.inflect(@inflection_name, @word, '連用形').should == '死に' 977 | end 978 | 979 | it 'inflects to 連用タ接続' do 980 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '死んだ' 981 | end 982 | 983 | it 'inflects to 終止形' do 984 | @inflector.inflect(@inflection_name, @word, '終止形').should == '死ぬ' 985 | end 986 | 987 | it 'inflects to 仮定形' do 988 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '死ね' 989 | end 990 | 991 | it 'inflects to 仮定縮約' do 992 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '死にゃ' 993 | end 994 | 995 | it 'inflects to 命令形' do 996 | @inflector.inflect(@inflection_name, @word, '命令形').should == '死ね' 997 | end 998 | end 999 | 1000 | context 'with 四段・ハ行' do 1001 | before do 1002 | @inflection_name = '四段・ハ行' 1003 | @word = '思ふ' 1004 | end 1005 | 1006 | it 'inflects to 未然形' do 1007 | @inflector.inflect(@inflection_name, @word, '未然形').should == '思は' 1008 | end 1009 | 1010 | it 'inflects to 未然ウ接続' do 1011 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '思ほ' 1012 | end 1013 | 1014 | it 'inflects to 未然ヌ接続' do 1015 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '思は' 1016 | end 1017 | 1018 | it 'inflects to 未然レル接続' do 1019 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '思は' 1020 | end 1021 | 1022 | it 'inflects to 連用形' do 1023 | @inflector.inflect(@inflection_name, @word, '連用形').should == '思ひ' 1024 | end 1025 | 1026 | it 'inflects to 連用タ接続' do 1027 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '思った' 1028 | end 1029 | 1030 | it 'inflects to 終止形' do 1031 | @inflector.inflect(@inflection_name, @word, '終止形').should == '思ふ' 1032 | end 1033 | 1034 | it 'inflects to 仮定形' do 1035 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '思へ' 1036 | end 1037 | 1038 | it 'inflects to 仮定縮約' do 1039 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '思ひゃ' 1040 | end 1041 | 1042 | it 'inflects to 命令形' do 1043 | @inflector.inflect(@inflection_name, @word, '命令形').should == '思へ' 1044 | end 1045 | end 1046 | 1047 | context 'with 五段・バ行' do 1048 | before do 1049 | @inflection_name = '五段・バ行' 1050 | @word = '遊ぶ' 1051 | end 1052 | 1053 | it 'inflects to 未然形' do 1054 | @inflector.inflect(@inflection_name, @word, '未然形').should == '遊ば' 1055 | end 1056 | 1057 | it 'inflects to 未然ウ接続' do 1058 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '遊ぼ' 1059 | end 1060 | 1061 | it 'inflects to 未然ヌ接続' do 1062 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '遊ば' 1063 | end 1064 | 1065 | it 'inflects to 未然レル接続' do 1066 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '遊ば' 1067 | end 1068 | 1069 | it 'inflects to 連用形' do 1070 | @inflector.inflect(@inflection_name, @word, '連用形').should == '遊び' 1071 | end 1072 | 1073 | it 'inflects to 連用タ接続' do 1074 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '遊んだ' 1075 | end 1076 | 1077 | it 'inflects to 終止形' do 1078 | @inflector.inflect(@inflection_name, @word, '終止形').should == '遊ぶ' 1079 | end 1080 | 1081 | it 'inflects to 仮定形' do 1082 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '遊べ' 1083 | end 1084 | 1085 | it 'inflects to 仮定縮約' do 1086 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '遊びゃ' 1087 | end 1088 | 1089 | it 'inflects to 命令形' do 1090 | @inflector.inflect(@inflection_name, @word, '命令形').should == '遊べ' 1091 | end 1092 | end 1093 | 1094 | context 'with 五段・マ行' do 1095 | before do 1096 | @inflection_name = '五段・マ行' 1097 | @word = '編む' 1098 | end 1099 | 1100 | it 'inflects to 未然形' do 1101 | @inflector.inflect(@inflection_name, @word, '未然形').should == '編ま' 1102 | end 1103 | 1104 | it 'inflects to 未然ウ接続' do 1105 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '編も' 1106 | end 1107 | 1108 | it 'inflects to 未然ヌ接続' do 1109 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '編ま' 1110 | end 1111 | 1112 | it 'inflects to 未然レル接続' do 1113 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '編ま' 1114 | end 1115 | 1116 | it 'inflects to 連用形' do 1117 | @inflector.inflect(@inflection_name, @word, '連用形').should == '編み' 1118 | end 1119 | 1120 | it 'inflects to 連用タ接続' do 1121 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '編んだ' 1122 | end 1123 | 1124 | it 'inflects to 終止形' do 1125 | @inflector.inflect(@inflection_name, @word, '終止形').should == '編む' 1126 | end 1127 | 1128 | it 'inflects to 仮定形' do 1129 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '編め' 1130 | end 1131 | 1132 | it 'inflects to 仮定縮約' do 1133 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '編みゃ' 1134 | end 1135 | 1136 | it 'inflects to 命令形' do 1137 | @inflector.inflect(@inflection_name, @word, '命令形').should == '編め' 1138 | end 1139 | end 1140 | 1141 | context 'with 五段・ラ行' do 1142 | before do 1143 | @inflection_name = '五段・ラ行' 1144 | @word = '走る' 1145 | end 1146 | 1147 | it 'inflects to 未然形' do 1148 | @inflector.inflect(@inflection_name, @word, '未然形').should == '走ら' 1149 | end 1150 | 1151 | it 'inflects to 未然ウ接続' do 1152 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '走ろ' 1153 | end 1154 | 1155 | it 'inflects to 未然ヌ接続' do 1156 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '走ら' 1157 | end 1158 | 1159 | it 'inflects to 未然レル接続' do 1160 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '走ら' 1161 | end 1162 | 1163 | it 'inflects to 連用形' do 1164 | @inflector.inflect(@inflection_name, @word, '連用形').should == '走り' 1165 | end 1166 | 1167 | it 'inflects to 連用タ接続' do 1168 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '走った' 1169 | end 1170 | 1171 | it 'inflects to 終止形' do 1172 | @inflector.inflect(@inflection_name, @word, '終止形').should == '走る' 1173 | end 1174 | 1175 | it 'inflects to 仮定形' do 1176 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '走れ' 1177 | end 1178 | 1179 | it 'inflects to 仮定縮約' do 1180 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '走りゃ' 1181 | end 1182 | 1183 | it 'inflects to 命令形' do 1184 | @inflector.inflect(@inflection_name, @word, '命令形').should == '走れ' 1185 | end 1186 | end 1187 | 1188 | context 'with 五段・ラ行特殊' do 1189 | before do 1190 | @inflection_name = '五段・ラ行特殊' 1191 | @word = 'なさる' 1192 | end 1193 | 1194 | it 'inflects to 未然形' do 1195 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'なさら' 1196 | end 1197 | 1198 | it 'inflects to 未然ウ接続' do 1199 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == 'なさろ' 1200 | end 1201 | 1202 | it 'inflects to 未然ヌ接続' do 1203 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == 'なさら' 1204 | end 1205 | 1206 | it 'inflects to 未然レル接続' do 1207 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == 'なさら' 1208 | end 1209 | 1210 | it 'inflects to 連用形' do 1211 | @inflector.inflect(@inflection_name, @word, '連用形').should == 'なさい' 1212 | end 1213 | 1214 | it 'inflects to 連用タ接続' do 1215 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == 'なさった' 1216 | end 1217 | 1218 | it 'inflects to 終止形' do 1219 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'なさる' 1220 | end 1221 | 1222 | it 'inflects to 仮定形' do 1223 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'なされ' 1224 | end 1225 | 1226 | it 'inflects to 仮定縮約' do 1227 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == 'なさりゃ' 1228 | end 1229 | 1230 | it 'inflects to 命令形' do 1231 | @inflector.inflect(@inflection_name, @word, '命令形').should == 'なさい' 1232 | end 1233 | end 1234 | 1235 | context 'with 五段・ワ行ウ音便' do 1236 | before do 1237 | @inflection_name = '五段・ワ行ウ音便' 1238 | @word = '乞う' 1239 | end 1240 | 1241 | it 'inflects to 未然形' do 1242 | @inflector.inflect(@inflection_name, @word, '未然形').should == '乞わ' 1243 | end 1244 | 1245 | it 'inflects to 未然ウ接続' do 1246 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '乞お' 1247 | end 1248 | 1249 | it 'inflects to 未然ヌ接続' do 1250 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '乞わ' 1251 | end 1252 | 1253 | it 'inflects to 未然レル接続' do 1254 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '乞わ' 1255 | end 1256 | 1257 | it 'inflects to 連用形' do 1258 | @inflector.inflect(@inflection_name, @word, '連用形').should == '乞い' 1259 | end 1260 | 1261 | it 'inflects to 連用タ接続' do 1262 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '乞うた' 1263 | end 1264 | 1265 | it 'inflects to 終止形' do 1266 | @inflector.inflect(@inflection_name, @word, '終止形').should == '乞う' 1267 | end 1268 | 1269 | it 'inflects to 仮定形' do 1270 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '乞え' 1271 | end 1272 | 1273 | it 'inflects to 仮定縮約' do 1274 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '乞や' 1275 | end 1276 | 1277 | it 'inflects to 命令形' do 1278 | @inflector.inflect(@inflection_name, @word, '命令形').should == '乞え' 1279 | end 1280 | end 1281 | 1282 | context 'with 五段・ワ行促音便' do 1283 | before do 1284 | @inflection_name = '五段・ワ行促音便' 1285 | @word = '誘う' 1286 | end 1287 | 1288 | it 'inflects to 未然形' do 1289 | @inflector.inflect(@inflection_name, @word, '未然形').should == '誘わ' 1290 | end 1291 | 1292 | it 'inflects to 未然ウ接続' do 1293 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == '誘お' 1294 | end 1295 | 1296 | it 'inflects to 未然ヌ接続' do 1297 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == '誘わ' 1298 | end 1299 | 1300 | it 'inflects to 未然レル接続' do 1301 | @inflector.inflect(@inflection_name, @word, '未然レル接続').should == '誘わ' 1302 | end 1303 | 1304 | it 'inflects to 連用形' do 1305 | @inflector.inflect(@inflection_name, @word, '連用形').should == '誘い' 1306 | end 1307 | 1308 | it 'inflects to 連用タ接続' do 1309 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == '誘った' 1310 | end 1311 | 1312 | it 'inflects to 終止形' do 1313 | @inflector.inflect(@inflection_name, @word, '終止形').should == '誘う' 1314 | end 1315 | 1316 | it 'inflects to 仮定形' do 1317 | @inflector.inflect(@inflection_name, @word, '仮定形').should == '誘え' 1318 | end 1319 | 1320 | it 'inflects to 仮定縮約' do 1321 | @inflector.inflect(@inflection_name, @word, '仮定縮約').should == '誘や' 1322 | end 1323 | 1324 | it 'inflects to 命令形' do 1325 | @inflector.inflect(@inflection_name, @word, '命令形').should == '誘え' 1326 | end 1327 | end 1328 | end 1329 | 1330 | context 'with 特殊・ナイ' do 1331 | before do 1332 | @inflection_name = '特殊・ナイ' 1333 | @word = 'ない' 1334 | end 1335 | 1336 | it 'inflects to 未然ウ接続' do 1337 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == 'なかろ' 1338 | end 1339 | 1340 | it 'inflects to 未然ヌ接続' do 1341 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == 'なから' 1342 | end 1343 | 1344 | it 'inflects to 連用タ接続' do 1345 | @inflector.inflect(@inflection_name, @word, '連用タ接続').should == 'なかっ' 1346 | end 1347 | 1348 | it 'inflects to 連用テ接続' do 1349 | @inflector.inflect(@inflection_name, @word, '連用テ接続').should == 'なく' 1350 | end 1351 | 1352 | it 'inflects to 連用デ接続' do 1353 | @inflector.inflect(@inflection_name, @word, '連用デ接続').should == 'ない' 1354 | end 1355 | 1356 | it 'inflects to 連用ゴザイ接続' do 1357 | @inflector.inflect(@inflection_name, @word, '連用ゴザイ接続').should == 'のう' 1358 | end 1359 | 1360 | it 'inflects to 終止形' do 1361 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'ない' 1362 | end 1363 | 1364 | it 'inflects to 音便終止形' do 1365 | @inflector.inflect(@inflection_name, @word, '音便終止形').should == 'ねえ' 1366 | end 1367 | 1368 | it 'inflects to 体言接続' do 1369 | @inflector.inflect(@inflection_name, @word, '体言接続').should == 'なき' 1370 | end 1371 | 1372 | it 'inflects to 仮定形' do 1373 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'なけれ' 1374 | end 1375 | 1376 | it 'inflects to 仮定縮約1' do 1377 | @inflector.inflect(@inflection_name, @word, '仮定縮約1').should == 'なけりゃ' 1378 | end 1379 | 1380 | it 'inflects to 仮定縮約2' do 1381 | @inflector.inflect(@inflection_name, @word, '仮定縮約2').should == 'なきゃ' 1382 | end 1383 | 1384 | it 'inflects to ガル接続' do 1385 | @inflector.inflect(@inflection_name, @word, 'ガル接続').should == 'な' 1386 | end 1387 | 1388 | it 'inflects to 命令形' do 1389 | @inflector.inflect(@inflection_name, @word, '命令形').should == 'なかれ' 1390 | end 1391 | end 1392 | 1393 | context 'with 特殊・タイ' do 1394 | before do 1395 | @inflection_name = '特殊・タイ' 1396 | @word = 'たい' 1397 | end 1398 | 1399 | it 'inflects to 未然ウ接続' do 1400 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == 'たかろ' 1401 | end 1402 | 1403 | it 'inflects to 未然ヌ接続' do 1404 | @inflector.inflect(@inflection_name, @word, '未然ヌ接続').should == 'たから' 1405 | end 1406 | 1407 | it 'inflects to 連用タ接続' do 1408 | @inflector.inflect(@inflection_name, @word, '連用タ接続').should == 'たかっ' 1409 | end 1410 | 1411 | it 'inflects to 連用テ接続' do 1412 | @inflector.inflect(@inflection_name, @word, '連用テ接続').should == 'たく' 1413 | end 1414 | 1415 | it 'inflects to 連用ゴザイ接続' do 1416 | @inflector.inflect(@inflection_name, @word, '連用ゴザイ接続').should == 'とう' 1417 | end 1418 | 1419 | it 'inflects to 終止形' do 1420 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'たい' 1421 | end 1422 | 1423 | it 'inflects to 音便終止形' do 1424 | @inflector.inflect(@inflection_name, @word, '音便終止形').should == 'てえ' 1425 | end 1426 | 1427 | it 'inflects to 体言接続' do 1428 | @inflector.inflect(@inflection_name, @word, '体言接続').should == 'たき' 1429 | end 1430 | 1431 | it 'inflects to 仮定形' do 1432 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'たけれ' 1433 | end 1434 | 1435 | it 'inflects to 仮定縮約1' do 1436 | @inflector.inflect(@inflection_name, @word, '仮定縮約1').should == 'たけりゃ' 1437 | end 1438 | 1439 | it 'inflects to 仮定縮約2' do 1440 | @inflector.inflect(@inflection_name, @word, '仮定縮約2').should == 'たきゃ' 1441 | end 1442 | 1443 | it 'inflects to ガル接続' do 1444 | @inflector.inflect(@inflection_name, @word, 'ガル接続').should == 'た' 1445 | end 1446 | end 1447 | 1448 | context 'with 特殊・デス' do 1449 | before do 1450 | @inflection_name = '特殊・デス' 1451 | @word = 'です' 1452 | end 1453 | 1454 | it 'inflects to 未然形' do 1455 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'でしょ' 1456 | end 1457 | 1458 | it 'inflects to 連用形' do 1459 | @inflector.inflect(@inflection_name, @word, '連用形').should == 'でし' 1460 | end 1461 | 1462 | it 'inflects to 終止形' do 1463 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'です' 1464 | end 1465 | end 1466 | 1467 | context 'with 特殊・マス' do 1468 | before do 1469 | @inflection_name = '特殊・マス' 1470 | @word = 'ます' 1471 | end 1472 | 1473 | it 'inflects to 未然形' do 1474 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'ませ' 1475 | end 1476 | 1477 | it 'inflects to 未然ウ接続' do 1478 | @inflector.inflect(@inflection_name, @word, '未然ウ接続').should == 'ましょ' 1479 | end 1480 | 1481 | it 'inflects to 連用形' do 1482 | @inflector.inflect(@inflection_name, @word, '連用形').should == 'まし' 1483 | end 1484 | 1485 | it 'inflects to 終止形' do 1486 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'ます' 1487 | end 1488 | 1489 | it 'inflects to 仮定形' do 1490 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'ますれ' 1491 | end 1492 | 1493 | it 'inflects to 命令形' do 1494 | @inflector.inflect(@inflection_name, @word, '命令形').should == 'ませ' 1495 | end 1496 | end 1497 | 1498 | context 'with 特殊・タ' do 1499 | before do 1500 | @inflection_name = '特殊・タ' 1501 | @word = 'た' 1502 | end 1503 | 1504 | it 'inflects to 未然形' do 1505 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'たろ' 1506 | end 1507 | 1508 | it 'inflects to 終止形' do 1509 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'た' 1510 | end 1511 | 1512 | it 'inflects to 仮定形' do 1513 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'たら' 1514 | end 1515 | end 1516 | 1517 | context 'with 特殊・ダ' do 1518 | before do 1519 | @inflection_name = '特殊・ダ' 1520 | @word = 'だ' 1521 | end 1522 | 1523 | it 'inflects to 未然形' do 1524 | @inflector.inflect(@inflection_name, @word, '未然形').should == 'だろ' 1525 | end 1526 | 1527 | it 'inflects to 連用形' do 1528 | @inflector.inflect(@inflection_name, @word, '連用形').should == 'で' 1529 | end 1530 | 1531 | it 'inflects to 連用タ接続' do 1532 | @inflector.inflect(@inflection_name, @word, '連用タ接続', :following => 'た').should == 'だった' 1533 | end 1534 | 1535 | it 'inflects to 終止形' do 1536 | @inflector.inflect(@inflection_name, @word, '終止形').should == 'だ' 1537 | end 1538 | 1539 | it 'inflects to 体言接続' do 1540 | @inflector.inflect(@inflection_name, @word, '体言接続').should == 'な' 1541 | end 1542 | 1543 | it 'inflects to 仮定形' do 1544 | @inflector.inflect(@inflection_name, @word, '仮定形').should == 'なら' 1545 | end 1546 | 1547 | it 'inflects to 命令形' do 1548 | @inflector.inflect(@inflection_name, @word, '命令形').should == 'なれ' 1549 | end 1550 | end 1551 | end 1552 | --------------------------------------------------------------------------------