module Expressive class Scope def initialize(parent = {}) @parent = parent @symbols = {} end def [](name) @symbols[name] || @parent[name] end def []=(name, value) @symbols[name] = value end def merge(scope) @symbols.merge!(scope) end def override_scope(scope) scope.merge!(@symbols) @symbols = scope end def retrieve_scope @symbols end def define(name, &block) self[name] = Function.new(&block) end def syntax(name, &block) self[name] = Syntax.new(&block) end end class Webhook def initialize(verb, url, params) @verb, @url, @params = verb, url, params end def execute self.send(@verb) end private def post RestClient.post(@url, @params) end def get RestClient.get(@url, {params: @params}) end def put RestClient.put(@url, @params) end end class TopLevel < Scope def initialize super syntax('set') do |scope, cells| scope[cells.first.text_value] = cells[1].eval(scope) end syntax('post') do |scope, cells| perform_webhook(:post, scope, cells) end syntax('put') do |scope, cells| perform_webhook(:put, scope, cells) end syntax('get') do |scope, cells| perform_webhook(:get, scope, cells) end define('+') {|a,b| a.to_f + b.to_f } define('-') {|a,b| a.to_f - b.to_f } define('*') {|a,b| a.to_f * b.to_f } define('/') {|a,b| a.to_f / b.to_f } define('=') {|a,b| a == b } define('>') {|a,b| a.to_f > b.to_f } define('<') {|a,b| a.to_f < b.to_f } define('>=') {|a,b| a.to_f >= b.to_f } define('<=') {|a,b| a.to_f <= b.to_f } define('and') {|a,b| !!a && !!b } define('or') {|a,b| !!a || !!b } define('sum') { |*args| args.flatten.map(&:to_f).reduce(:+) } define('if') { |*args| args.compact!; args[0] ? args[1] : args[2] } end def to_hash h = self.retrieve_scope.dup h.delete_if{|k, v| v.kind_of?(Expressive::Function)} end private #(post "http://example.com" name age other) #(get "http://example.com" "*") def perform_webhook(verb, scope, cells) url = cells.shift.text_value.gsub('"', '') params = create_webhook_parameters(scope, cells) begin response = Webhook.new(verb, url, params).execute scope = scope.merge(response) if response.is_a?(Hash) rescue RestClient::Exception => e scope['_errors'] = e.message end scope end def create_webhook_parameters(scope, cells) if cells.first && cells.first.text_value.gsub('"', '') == '*' scope.to_hash else cells.inject({}) do |params, key| params[key.text_value] = scope[key.text_value] params end end end end end