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
# 整数を返すメソッド
#
def integer
- needs(:min, :max, :minus)
create_integer(options[:min], options[:max], options[:minus]).to_s
end
# 小数を返すメソッド
#
def decimal
- needs(:min, :max, :minus, :digits)
use_integer = rand(3) == 0
integer_part = 0
unless use_integer
# 分数を返すメソッド
#
def fraction
- needs(:numerator_min, :numerator_max, :denominator_min, :denominator_max, :minus)
begin
numerator = numerator_part
denominator = denominator_part
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
@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
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
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
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
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
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
# [_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
# [_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
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
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
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
include Utilities
+ option :x, ['x']
+
#
# 前処理を行った後に式を生成する
# 各ジェネレータからこのメソッドを呼ぶ必要がある
#
- def do_generate(settings)
- defaults = {:x => ['x']}.merge(settings)
- @options = options(defaults)
+ def do_generate
expression
end
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)
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
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
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
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
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 }
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
: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
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
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
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
it 'call expression' do
subject.should_receive(:expression)
- subject.__send__(:do_generate, {})
+ subject.__send__(:do_generate)
end
context 'discriminant' do
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
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