Skip to content

Commit

Permalink
Merge pull request #61 from project-eutopia/puts
Browse files Browse the repository at this point in the history
Support for `puts` in expressions
  • Loading branch information
project-eutopia committed Jan 4, 2018
2 parents 6322e5f + b887362 commit 39ee5b6
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 3 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,14 @@ calculator.evaluate("replace(diff(f(2*t, t+1), t), t, 3)")
#=> 1+8*3
```

There is also a `puts` function that can be used to output the result of an expression to STDOUT.

```ruby
calculator = Keisan::Calculator.new
calculator.evaluate("x = 5")
calculator.evaluate("puts x**2") # prints "25\n" to STDOUT
```

### Adding custom variables and functions

The `Keisan::Calculator` class has a single `Keisan::Context` object in its `context` attribute. This class is used to store local variables and functions. These can be stored using either the `define_variable!` or `define_function!` methods, or by using the assignment operator `=` in an expression that is evaluated. As an example of pre-defining some variables and functions, see the following
Expand Down
2 changes: 2 additions & 0 deletions lib/keisan/functions/default_registry.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative "let"
require_relative "puts"

require_relative "if"
require_relative "while"
Expand Down Expand Up @@ -46,6 +47,7 @@ def self.registry

def self.register_defaults!(registry)
registry.register!(:let, Let.new, force: true)
registry.register!(:puts, Puts.new, force: true)

registry.register!(:if, If.new, force: true)
registry.register!(:while, While.new, force: true)
Expand Down
23 changes: 23 additions & 0 deletions lib/keisan/functions/puts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Keisan
module Functions
class Puts < Function
def initialize
super("puts", 1)
end

def value(ast_function, context = nil)
evaluate(ast_function, context)
end

def evaluate(ast_function, context = nil)
validate_arguments!(ast_function.children.count)
puts ast_function.children.first.evaluate(context).to_s
Keisan::AST::Null.new
end

def simplify(ast_function, context = nil)
evaluate(ast_function, context)
end
end
end
end
2 changes: 1 addition & 1 deletion lib/keisan/parser.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Keisan
class Parser
KEYWORDS = %w(let).freeze
KEYWORDS = %w(let puts).freeze

attr_reader :tokens, :components

Expand Down
40 changes: 40 additions & 0 deletions spec/keisan/puts_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require "spec_helper"

RSpec.describe Keisan::Functions::Puts do
let(:calculator) { Keisan::Calculator.new }

it "outputs to STDOUT" do
expect { calculator.evaluate("puts 123") }.to output("123\n").to_stdout
expect { calculator.evaluate("puts(x**2 + 1)") }.to output("(x**2)+1\n").to_stdout
calculator.evaluate("x = 2")
expect { calculator.evaluate("puts(x**2 + 1)") }.to output("5\n").to_stdout
end

describe "evaluate" do
it "returns null" do
expect {
ast = calculator.ast("puts x = 5")
expect(ast.evaluate).to eq Keisan::AST::Null.new
}.to output("5\n").to_stdout
end

it "does evaluation of arguments" do
expect { calculator.evaluate("puts(x = 12)") }.to output("12\n").to_stdout
expect(calculator.evaluate("x")).to eq 12
end
end

describe "#value and #simplify call evaluate" do
it "value calls evaluate" do
expect_any_instance_of(Keisan::Functions::Puts).to receive(:evaluate).and_return(Keisan::AST::Null.new)
ast = calculator.ast("puts x = 5")
expect(ast.value).to eq Keisan::AST::Null.new
end

it "simplify calls evaluate" do
expect_any_instance_of(Keisan::Functions::Puts).to receive(:evaluate).and_return(Keisan::AST::Null.new)
ast = calculator.ast("puts x = 5")
expect(ast.simplify).to eq Keisan::AST::Null.new
end
end
end
8 changes: 6 additions & 2 deletions spec/readme_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
digest = Digest::SHA256.hexdigest(content)

# cat README.md | sha256sum
expected_digest = "ceca07925099af54db28079b7ae408bbf1d478ebe96c26c0deb1c1b0a458e194"
expected_digest = "ec824b6fb3574ec4c5ffab47e4c39c86573fad0f3fd7c73a8c24e55c32fee9fc"
if digest != expected_digest
raise "Invalid README file detected with SHA256 digest of #{digest}. Use command `cat README.md | sha256sum` to get correct digest if your changes to the README are safe. Aborting README test."
end
Expand All @@ -25,7 +25,11 @@

outputs = code_block.map do |line|
begin
eval(line, b)
# Capture output of any `puts` statements
$stdout = StringIO.new
result = eval(line, b)
$stdout = STDOUT
result
rescue Keisan::Exceptions::BaseError => e
e
end
Expand Down

0 comments on commit 39ee5b6

Please sign in to comment.