OSDN Git Service

change option system for generators
authorTomohiro Nishimura <tomohiro68@gmail.com>
Mon, 8 Mar 2010 04:51:17 +0000 (13:51 +0900)
committerTomohiro Nishimura <tomohiro68@gmail.com>
Mon, 8 Mar 2010 04:51:17 +0000 (13:51 +0900)
21 files changed:
lib/mint/generator/arithmetic_base.rb
lib/mint/generator/base.rb
lib/mint/generator/complex_fractional_arithmetic.rb
lib/mint/generator/complex_number_arithmetic.rb
lib/mint/generator/decimal_arithmetic.rb
lib/mint/generator/expansion.rb
lib/mint/generator/factorization.rb
lib/mint/generator/fractional_arithmetic.rb
lib/mint/generator/fractional_expression_arithmetic.rb
lib/mint/generator/high_order_expression_base.rb
lib/mint/generator/linear_function_graph.rb
lib/mint/generator/ordinary_arithmetic.rb
lib/mint/generator/partial_fraction_expansion.rb
lib/mint/generator/quadratic_equation.rb
lib/mint/generator/square_root_arithmetic.rb
spec/generator/arithmetic_base_spec.rb
spec/generator/base_spec.rb
spec/generator/complex_number_arithmetic_spec.rb
spec/generator/high_order_expression_base_spec.rb
spec/generator/square_root_arithmetic_spec.rb
tasks/spec_statistics.rb

index 9c17727..9495b92 100644 (file)
@@ -14,14 +14,14 @@ module Mint::Generator
 
     include Utilities
 
+    option :term_number, 2
+    option :operators, DEFAULT_OPERATORS
+
     #
     # 前処理を行った後に式を生成する。
     # 各ジェネレータからこのメソッドを呼ぶ必要がある
     #
-    def do_generate(settings = {})
-      defaults = {:term_number => 2, :operators => DEFAULT_OPERATORS}
-      defaults.merge!(settings)
-      @options = options(defaults)
+    def do_generate
       String(expression).gsub(%r! (-[0-9./]+)!, ' (\\1)')
     end
 
@@ -60,7 +60,6 @@ module Mint::Generator
     # 整数を返すメソッド
     #
     def integer
-      needs(:min, :max, :minus)
       create_integer(options[:min], options[:max], options[:minus]).to_s
     end
 
@@ -68,7 +67,6 @@ module Mint::Generator
     # 小数を返すメソッド
     #
     def decimal
-      needs(:min, :max, :minus, :digits)
       use_integer = rand(3) == 0
       integer_part = 0
       unless use_integer
@@ -82,7 +80,6 @@ module Mint::Generator
     # 分数を返すメソッド
     #
     def fraction
-      needs(:numerator_min, :numerator_max, :denominator_min, :denominator_max, :minus)
       begin
         numerator   = numerator_part
         denominator = denominator_part
@@ -97,13 +94,6 @@ module Mint::Generator
     def denominator_part
       create_integer(options[:denominator_min], options[:denominator_max], false)
     end
-
-    def needs(*keys)
-      errors = keys.map {|key| options.has_key?(key) ? nil : key }.compact
-      unless errors.size.zero?
-        raise "This operand need these options: #{errors.join(', ')}"
-      end
-    end
   end
 end
 
index 65f7b6d..0f53e3e 100644 (file)
@@ -14,13 +14,13 @@ module Mint::Generator
       @validations << pattern
     end
 
-    def initialize(amount = 1, options = {})
+    def initialize(amount = 1)
       @validations = @@validations[self.class.name] || []
       @amount = amount
     end
 
     def generate(options = {})
-      set_options options
+      self.options = options
       Array(@amount.times.map { generated_problem })
     end
 
@@ -55,12 +55,23 @@ module Mint::Generator
       result
     end
 
-    def set_options(options)
-      @options = options
+    attr_writer :options
+
+    def options
+      @@default_options.merge(@options)
+    end
+
+    def do_with(options)
+      original = @options
+      @options = original.merge(options)
+      result = yield
+      @options = original
+      result
     end
 
-    def options(default = {})
-      default.merge(@options)
+    def self.option(key, value)
+      @@default_options ||= {}
+      @@default_options[key] = value
     end
   end
 end
index 2156742..295b477 100644 (file)
@@ -18,21 +18,21 @@ module Mint::Generator
 
     private
 
+    option :numerator_term_min,   1
+    option :numerator_term_max,   1
+    option :denominator_term_min, 2
+    option :denominator_term_max, 2
+    option :operators,            %w[ + - * ]
+
+    # for inner use
+    option :numerator_min,   1
+    option :numerator_max,   9
+    option :denominator_min, 1
+    option :denominator_max, 9
+    option :minus,           false
+
     def generate_problem
-      defaults = {
-        :numerator_term_min   => 1,
-        :numerator_term_max   => 1,
-        :denominator_term_min => 2,
-        :denominator_term_max => 2,
-        :operators => %w[ + - * ],
-        # for inner use
-        :numerator_min   => 1,
-        :numerator_max   => 9,
-        :denominator_min => 1,
-        :denominator_max => 9,
-        :minus => false,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def expression
@@ -43,15 +43,11 @@ module Mint::Generator
     end
 
     def operand
-      @options = options(:min => 1, :max => 9, :minus => false)
-      integer
+      opts = { :min => 1, :max => 9, :minus => false }
+      do_with(opts) { integer }
     end
 
-    [
-      :numerator,
-      :denominator
-
-    ].each do |name|
+    [:numerator, :denominator].each do |name|
       define_method(name) do
         result = []
         term_number(name).times do
index 313320c..183f126 100644 (file)
@@ -17,16 +17,15 @@ module Mint::Generator
 
     private
 
+    option :min,             1
+    option :max,             9
+    option :fractional_mode, false
+    option :operators,       %w[ * / ]
+
+
     def generate_problem
-      defaults = {
-        :min => 1, :max => 9,
-        :fractional_mode => false,
-        :operators => %w[ * / ]
-      }
-      if options[:fractional_mode]
-        @options[:operators] = %w[ + - ]
-      end
-      do_generate(defaults)
+      opts = options[:fractional_mode] ?  {:operators => %w[ + - ]} : {}
+      do_with(opts) { do_generate }
     end
 
     def operand
index 3960413..f564c84 100644 (file)
@@ -18,14 +18,13 @@ module Mint::Generator
 
     private
 
+    option :minus,  true
+    option :min,    0
+    option :max,    100
+    option :digits, 2
+
     def generate_problem
-      defaults = {
-        :minus  => true,
-        :min    => 0,
-        :max    => 100,
-        :digits => 2,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def operand
index c28b244..38cbf55 100644 (file)
@@ -10,21 +10,22 @@ module Mint::Generator
   #               [_order_min_] 次数の最小値 (ex. 2)
   #               [_order_max_] 次数の最大値 (ex. 3)
   #               [_x_] 使用する変数 (ex. ['x'] / [['x', 'y']])
-  #               [_factor_minus_] 真なら整数部に負の数字を使用する (ex. true)
   #               [_factor_min_] 整数部の最小値 (ex. 0)
   #               [_factor_max_] 整数部の最大値 (ex. 100)
+  #               [_factor_minus_] 真なら整数部に負の数字を使用する (ex. true)
   #
   class Expansion < HighOrderExpression
 
     private
+
+    option :order_min,    2
+    option :order_max,    3
+    option :factor_min,   1
+    option :factor_max,   100
+    option :factor_minus, true
+
     def generate_problem
-      defaults = {
-        :order_min => 2, :order_max => 3,
-        :factor_minus => true,
-        :factor_min   => 1,
-        :factor_max   => 100,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def expression
index ad2c8c1..2e52851 100644 (file)
@@ -11,9 +11,9 @@ module Mint::Generator
   #               [_order_min_] 次数の最小値 (ex. 2)
   #               [_order_max_] 次数の最大値 (ex. 3)
   #               [_x_] 使用する変数 (ex. ['x'] / [['x', 'y']])
-  #               [_factor_minus_] 真なら整数部に負の数を使用する (ex. true)
   #               [_factor_min_] 整数部の最小値 (ex. 0)
   #               [_factor_max_] 整数部の最大値 (ex. 100)
+  #               [_factor_minus_] 真なら整数部に負の数を使用する (ex. true)
   #
   class Factorization < HighOrderExpression
 
@@ -25,14 +25,15 @@ module Mint::Generator
     validation /\A(?:\d+)?([a-zA-Z])\^3 [+-] (?:\d+)?\1\^2([a-zA-Z]) [+-] (?:\d+)?\1\2\^2 [+-] (?:\d+)?\2\^3\z/
 
     private
+
+    option :order_min,    2
+    option :order_max,    3
+    option :factor_min,   1
+    option :factor_max,   100
+    option :factor_minus, true
+
     def generate_problem
-      defaults = {
-        :order_min => 2, :order_max => 3,
-        :factor_minus => true,
-        :factor_min   => 1,
-        :factor_max   => 100,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def expression
index 517dd15..23d84fe 100644 (file)
@@ -19,15 +19,14 @@ module Mint::Generator
 
     private
 
+    option :minus,           true
+    option :numerator_min,   1
+    option :numerator_max,   100
+    option :denominator_min, 2
+    option :denominator_max, 100
+
     def generate_problem
-      defaults = {
-        :minus           => true,
-        :numerator_min   => 1,
-        :numerator_max   => 100,
-        :denominator_min => 2,
-        :denominator_max => 100,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def expression
index 6495534..0088d85 100644 (file)
@@ -25,15 +25,18 @@ module Mint::Generator
 
     include Utilities
 
+    # TODO: I wanna set option for expression order
+    option :x,                    ['x']
+    option :numerator_term_min,   1
+    option :numerator_term_max,   1
+    option :denominator_term_min, 1
+    option :denominator_term_max, 1
+    option :factor_minus,         false
+    option :factor_min,           1
+    option :factor_max,           9
+
     def generate_problem
-      # TODO: I wanna set option for expression order
-      defaults = {
-        :x => ['x'],
-        :numerator_term_min   => 1, :numerator_term_max   => 1,
-        :denominator_term_min => 1, :denominator_term_max => 1,
-        :factor_minus => false, :factor_min => 1, :factor_max => 9,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def operand
index f1c2a8f..81eafaf 100644 (file)
@@ -11,13 +11,13 @@ module Mint::Generator
 
     include Utilities
 
+    option :x, ['x']
+
     #
     # 前処理を行った後に式を生成する
     # 各ジェネレータからこのメソッドを呼ぶ必要がある
     #
-    def do_generate(settings)
-      defaults = {:x => ['x']}.merge(settings)
-      @options = options(defaults)
+    def do_generate
       expression
     end
 
index 30004c6..2f33f85 100644 (file)
@@ -21,14 +21,16 @@ module Mint::Generator
 
     include Utilities
 
+    option :minus,           true
+    option :x_minus,         true
+    option :x_min,           0
+    option :x_max,           10
+    option :numerator_min,   1
+    option :numerator_max,   10
+    option :denominator_min, 1
+    option :denominator_max, 5
+
     def generate_problem
-      defaults = {
-        :minus => true,
-        :x_minus => true, :x_min => 0, :x_max => 10,
-        :numerator_min => 1, :numerator_max => 10,
-        :denominator_min => 1, :denominator_max => 5,
-      }
-      options = options(defaults)
       a = create_rational(options)
       b = create_rational(options)
       f = function(a, b)
index f632abc..acdef49 100644 (file)
@@ -17,9 +17,12 @@ module Mint::Generator
 
     private
 
+    option :minus, true
+    option :min,   0
+    option :max,   100
+
     def generate_problem
-      defaults = {:minus => true, :min => 0, :max => 100}
-      do_generate(defaults)
+      do_generate
     end
 
     def operand
index fcbd9f6..8ba6710 100644 (file)
@@ -26,31 +26,36 @@ module Mint::Generator
 
     include Utilities
 
+    option :order_min,         2
+    option :order_max,         2
+    option :x,                 ['x']
+    option :factor_minus,      false
+    option :factor_min,        1
+    option :factor_max,        100
+    option :coefficient_minus, false
+    option :coefficient_min,   1
+    option :coefficient_max,   1
+    option :numerator_minus,   false
+    option :numerator_min,     1
+    option :numerator_max,     1
+
     def generate_problem
-      defaults = {
-        :order_min         => 2,     :order_max       => 2, :x               => ['x'],
-        :factor_minus      => false, :factor_min      => 1, :factor_max      => 100,
-        :coefficient_minus => false, :coefficient_min => 1, :coefficient_max => 1,
-        :numerator_minus   => false, :numerator_min   => 1, :numerator_max   => 1,
-      }
-      targets = %w[order factor coefficient numerator]
-      options = min_max_order(options(defaults), targets)
-      expression(options)
+      expression
     end
 
-    def partial_fraction(options)
+    def partial_fraction
       numerator_part = create_integer(options[:numerator_min], options[:numerator_max], options[:numerator_minus])
-      denominator_part = expansion(options)
+      denominator_part = expansion
       "#{numerator_part}/#{denominator_part}"
     end
 
-    def expression(options)
+    def expression
       result = []
-      result << partial_fraction(options)
+      result << partial_fraction
       result.sample
     end
 
-    def expansion(options)
+    def expansion
       result = []
       order = create_integer(options[:order_min], options[:order_max], false)
       x = options[:x].sample
index 349970a..55b8d5f 100644 (file)
@@ -15,15 +15,13 @@ module Mint::Generator
   class QuadraticEquation < Base
 
     private
-    def generate_problem
-      defaults = {
-        :answer_type => :rational,
-        :r_max => 20,
-        :p_max => 12,
-        :q_max => 40,
-      }
-      set_options defaults.merge(options)
 
+    option :answer_type, :rational
+    option :r_max,       20
+    option :p_max,       12
+    option :q_max,       40
+
+    def generate_problem
       expression
     end
 
index 929c82e..ee46494 100644 (file)
@@ -27,15 +27,15 @@ module Mint::Generator
 
     private
 
+    option :min,             0
+    option :max,             30
+    option :operators,       %w[ + - ]
+    option :use_power,       false
+    option :single_term_min, 1
+    option :single_term_max, 2
     def generate_problem
-      defaults = {
-        :min => 0, :max => 30,
-        :operators => %w[ + - ],
-        :use_power => false,
-        :single_term_min => 1,
-        :single_term_max => 2,
-      }
-      do_generate(defaults)
+      do_generate
     end
 
     def term_number
index 7c58a2d..a14ee73 100644 (file)
@@ -8,7 +8,7 @@ module Mint::Generator
 
     def set_options(options = {})
       defaults = {:term_number => 1, :operators => ['@']}
-      subject.__send__(:set_options, defaults.merge(options))
+      subject.__send__(:options=, defaults.merge(options))
     end
 
     before { set_options }
@@ -65,22 +65,12 @@ module Mint::Generator
         def subject.create_integer(*args); 1 end
       end
 
-      it 'needs options' do
-        expect { subject.__send__(:needs, :hoge) }.
-          to raise_error("#{@msg} hoge")
-      end
-
       context 'integer' do
 
         it do
           set_options(:min => nil, :max => nil, :minus => nil)
           subject.__send__(:integer).should == @int
         end
-
-        it 'without options' do
-          expect { subject.__send__(:integer) }.
-            to raise_error("#{@msg} min, max, minus")
-        end
       end
 
       context 'decimal' do
@@ -93,11 +83,6 @@ module Mint::Generator
             :digits => 2)
           subject.__send__(:decimal).should match(/(?:#{@int}|0)\.\d\d?/)
         end
-
-        it 'without options' do
-          expect { subject.__send__(:decimal) }.
-            to raise_error("#{@msg} min, max, minus, digits")
-        end
       end
 
       context 'fraction' do
@@ -113,18 +98,6 @@ module Mint::Generator
           subject.should_receive(:denominator_part).and_return('b')
           subject.__send__(:fraction).should == "a/b"
         end
-
-        it 'without options' do
-          needs = [
-            :numerator_min,
-            :numerator_max,
-            :denominator_min,
-            :denominator_max,
-            :minus
-          ]
-          expect { subject.__send__(:fraction) }.
-            to raise_error("#{@msg} #{needs.join(', ')}")
-        end
       end
     end
   end
index 871b988..0e8b112 100644 (file)
@@ -96,44 +96,59 @@ module Mint
       end
     end
 
-    context 'set options' do
+    context 'options' do
 
       before do
         @options = { :range => (5..10) }
-        subject.should_receive(:generate_problem).with(no_args)
+        @defaults = [
+          [:test1, 'test1'],
+          [:test2, 'test2'],
+          [:test3, 'test3'],
+        ]
       end
 
       subject { Generator::Base.new }
 
-      it 'can set options' do
-        subject.should_receive(:set_options).with(@options)
-        subject.generate(@options)
-      end
-
-      it "doesn't need set options" do
-        subject.should_receive(:set_options).with({})
-        subject.generate
+      context 'set default options' do
+        before do
+          klass = subject.class
+          klass.__send__(:option, *@defaults[0])
+          klass.__send__(:option, *@defaults[1])
+          klass.__send__(:option, *@defaults[2])
+          @default_options = klass.__send__(:class_variable_get, :@@default_options)
+        end
+        it { @default_options.should include(*@defaults.map(&:first)) }
       end
 
       context 'refer options' do
-
-        before { subject.generate(@options) }
-
-        it 'refer optins' do
-          subject.__send__(:options).should == @options
+        before do
+          subject.__send__(:options=, @options)
+          @opts = subject.__send__(:options)
         end
+        it { @opts.should include(:range) }
+        it { @opts[:range].should == @options[:range] }
+        it { @opts.should include(:test1) }
+        it { @opts.should include(:test2) }
+        it { @opts.should include(:test3) }
+      end
 
-        it 'set default options' do
-          defaults = { :one => 1 }
-          result = subject.__send__(:options, defaults)
-          result.should have_key(:one)
+      context 'temporary change' do
+        before do
+          subject.__send__(:options=, @options)
+          @opts = {:tempo => 'rary'}
         end
-
-        it "dosn't ovewirte original" do
-          defaults = { :range => (10..20) }
-          result = subject.__send__(:options, defaults)
-          result[:range].should == @options[:range]
+        it do
+          subject.__send__(:do_with, @opts) do
+            current = subject.__send__(:options)
+            current.should include(@opts.keys[0])
+            current[@opts.keys[0]].should == @opts.values[0]
+          end
+        end
+        it do
+          subject.__send__(:do_with, @opts) {}
+          subject.__send__(:options).should_not include(@opts.keys[0])
         end
+        it { subject.__send__(:do_with, @opts) { 'milk tea' }.should == 'milk tea' }
       end
     end
 
index 2968e1d..9823c26 100644 (file)
@@ -15,28 +15,28 @@ module Mint::Generator
 
       it 'zero' do
         settings = @defaults.merge(:min => 0, :max => 0)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         result = subject.__send__(:create_complex_number)
         result.should match(/\A[2-9]\z/)
       end
 
       it 'one' do
         settings = @defaults.merge(:max => 1)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         result = subject.__send__(:create_complex_number)
         result.should match(/\A1 [\-+] %i\z/)
       end
 
       it 'general' do
         settings = @defaults.merge(:min => 2, :max => 9)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         result = subject.__send__(:create_complex_number)
         result.should match(/\A\d [\-+] \d%i\z/)
       end
 
       it 'conjugate complex' do
         settings = @defaults.merge(:max => 1)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         original = subject.__send__(:create_complex_number)
         conjugate = subject.__send__(:conjugate_complex, original)
         _, original_opt, _ = *original.split
index fa0aa85..ddcd173 100644 (file)
@@ -11,7 +11,7 @@ module Mint::Generator
 
     it 'call expression' do
       subject.should_receive(:expression)
-      subject.__send__(:do_generate, {})
+      subject.__send__(:do_generate)
     end
 
     context 'discriminant' do
index 1eeefc3..8318d4e 100644 (file)
@@ -15,27 +15,27 @@ module Mint::Generator
 
       it 'zero' do
         settings = @defaults.merge(:min => 0, :max => 0)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         result = subject.__send__(:create_square_root_number)
         result.should match(/\A[2-9]\z/)
       end
 
       it 'one' do
         settings = @defaults.merge(:min => 1, :max => 1)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         result = subject.__send__(:create_square_root_number)
         result.should match(/\A[2-9]\z/)
       end
 
       it 'without coefficient' do
-        subject.__send__(:set_options, @defaults)
+        subject.__send__(:options=, @defaults)
         result = subject.__send__(:create_square_root_number)
         result.should == 'sqrt(2)'
       end
 
       it 'with coefficient' do
         settings = @defaults.merge(:use_coefficient => true)
-        subject.__send__(:set_options, settings)
+        subject.__send__(:options=, settings)
         result = subject.__send__(:create_square_root_number)
         result.should match(/\A[2-9]?sqrt\(2\)\z/)
       end
index 5a7b524..cd061e1 100644 (file)
@@ -23,8 +23,8 @@ class SpecStatistics < CodeStatistics
         stats["lines"]     += 1
         stats["classes"]   += 1 if line =~ /class [A-Z]/
         stats["methods"]   += 1 if line =~ /def [a-z]/
-        stats["specs"]     += 1 if line.strip =~ /^it.*(do|\{)$/
-        stats["behaviors"] += 1 if line =~ /describe.*(do|\{)$/
+        stats["specs"]     += 1 if line =~ /it.*(do|\{)/
+        stats["behaviors"] += 1 if line =~ /describe.*(do|\{)/
         stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
       end
     end