class Object { """ Root class of Fancy's class hierarchy. All classes inherit from Object. """ def ++ other { """ @other Other object to concatenate its @String value with. @return @String concatenation of @String values of @self and @other. Returns the @String concatenation of @self and @other. Calls to_s on @self and @other and concatenates the results to a new @String. """ to_s + (other to_s) } def loop: block { """ @block @Block@ to be called endlessly (loop). Infinitely calls the block (loops). """ { true } while_true: block } def println { """ Same as: Console println: self Prints @self on @STDOUT, followed by a newline. """ Console println: to_s } def print { """ Same as: Console print: self Prints @self on STDOUT. """ Console print: to_s } def != other { """ @other Other object to compare against. @return @true if @self is not equal to @other, @false otherwise. Indicates, if two objects are not equal. """ self == other not } def if_true: block { """ @block @Block@ to be called. @return Value of calling @block with @self. Calls the @block (default behaviour). """ block call: [self] } def if_true: then_block else: else_block { """ @then_block @Block@ to be called. @else_block Does not get called (default behaviour). @return Value of calling @then_block with @self. Calls the @then_block (default behaviour). """ then_block call: [self] } def if_false: block { """ @return @nil Does nothing (default behaviour). """ nil } def if_false: then_block else: else_block { """ @then_block Does not get called (default behaviour). @else_block @Block@ to be called. @return Value of calling @else_block. Calls @else_block (default behaviour). """ else_block call } alias_method: 'if_nil: for: 'if_false: alias_method: 'if_nil:else: for: 'if_false:else: def nil? { """ @return @false. """ false } def false? { """ @return @false. """ false } def true? { """ @return @false. """ false } def to_a { """ @return @Array@ representation of @self. """ [self] } def to_i { """ @return @Fixnum@ representation of @self. """ 0 } def to_enum { """ @return @FancyEnumerator@ for @self using 'each: for iteration. """ FancyEnumerator new: self } def to_enum: iterator { """ @iterator Message to use for iteration on @self. @return @FancyEnumerator@ for @self using @iterator for iteration. """ FancyEnumerator new: self with: iterator } def and: other { """ @other Object or @Block@ (for short-circuit evaluation) to compare @self to. @return @other if both @self and @other are true-ish, @self otherwise. Boolean conjunction. If @self and @other are both true-ish (non-nil, non-false), returns @other. If @other is a @Block@, calls it and returns its return value. """ if_true: { { other = other call } if: (other is_a?: Block) other } else: { self } } def or: other { """ @other Object or @Block@ (for short-circuit evaluation) to compare @self to. @return @self if @self is true-ish, @other otherwise. Boolean disjunction. If @self is true-ish (non-nil, non-false) returns @self. Otherwise returns @other (if @other is a @Block@, calls it first and returns its return value) """ if_true: { self } else: { { other = other call } if: (other is_a?: Block) other } } def xor: other { """ @other @Object@ to compare @self against. @return @true if only one of @self and @other is true, @false otherwise. """ if_true: { other not } else: { other not not } } alias_method: ':&& for: 'and: alias_method: ':|| for: 'or: def if: cond then: block { """ Same as: cond if_true: block """ cond if_true: block } def if: cond then: then_block else: else_block { """ Same as: cond if_true: then_block else: else_block """ cond if_true: then_block else: else_block } def while: cond_block do: body_block { """ Same as: cond_block while_do: body_block """ cond_block while_do: body_block } def until: cond_block do: body_block { """ Same as: cond_block until_do: body_block """ cond_block until_do: body_block } def do: body_block while: cond_block { """ @body_block @Block@ to be called at least once and as long as @cond_block yields a true-ish value. @cond_block Condition @Block@ used to determine if @body_block@ should be called again. """ body_block call: [nil] cond_block while_do: body_block } def do: body_block until: cond_block { """ @body_block @Block@ to be called at least once and as long as @cond_block yields a false-ish value. @cond_block Condition @Block@ used to determine if @body_block@ should be called again. """ body_block call cond_block until_do: body_block } def unless: cond do: block { """ Same as: cond if_true: { nil } else: block """ cond if_true: { nil } else: block } def unless: cond do: block else: else_block { """ Same as: cond if_true: else_block else: block """ cond if_true: else_block else: block } def method: method_name { """ @return @Method@ with @method_name defined for @self, or @nil. Returns the method with a given name for self, if defined. """ method(message_name: method_name) } def documentation { """ @return @Fancy::Documentation@ object for @self. Returns the @Fancy::Documentation@ object for an Object. """ Fancy Documentation for: self } def documentation: docstring { """ @docstring New docstring for @self. Sets the documentation string for an Object. """ Fancy Documentation for: self is: docstring } def identity { """ @return @self. The identity method simply returns self. """ self } def returning: value do: block { """ @value Value that gets returned at the end. @block A @Block@ that gets called with @value before returning @value. @return @value Returns @value after calling @block with it. Useful for returning some object after using it, e.g.: # this will return [1,2] returning: [] do: |arr| { arr << 1 arr << 2 } """ val = value block call: [val] val } def if_responds? { """ @return RespondsToProxy for @self Returns a @RespondsToProxy@ for @self that forwards any messages only if @self responds to them. Example usage: # only send 'some_message: if object responds to it: object if_responds? some_message: some_parameter """ RespondsToProxy new: self } def backtick: str { """ This is the default implementation for backtick: which gets called when using the backtick syntax. For example: `cat README` Gets translated to the following message send: self backtick: \"cat README\" Which allows for custom implementations of the backtick: method, if needed. This default implementation works the same way as in Ruby, Perl or Bash. It returns the output of running the given string on the command line as a @String@. """ System pipe: str . read } def ? future { """ @future Future object to get the value from. @return Result of calling #value on @future. Calls #value on @future. Shortcut method. """ future value } def yield { """ Same as Fiber##yield. """ Fiber yield } def yield: values { """ Same as Fiber##yield: """ Fiber yield: values } def next { """ Skip to the next iteration. """ Fancy NextIteration new raise! } def next: value { """ @value Value for next iteration. Returns @value for current iteration and skip to the next one. """ Fancy NextIteration new: value . raise! } def break { """ Breaks / Stops current iteration. """ Fancy BreakIteration new raise! } def break: value { """ @value Value to return from iteration. Returns @value from iteratioen. """ Fancy BreakIteration new: value . raise! } def __spawn_actor__ { @__actor__active__ = true Actor spawn: { __actor__loop__ } } def __actor__loop__ { while: { @__actor__active__ } do: { sender = nil try { type, msg, sender = Actor receive msg, params = msg match type { case 'async -> self receive_message: msg with_params: params case 'future -> val = self receive_message: msg with_params: params sender completed: val } } catch Exception => e { { sender failed: e } if: sender die! e raise! } } } def __actor__die!__ { @__actor__active__ = false @__actor__ = nil } def __actor__ { @__actor__ = @__actor__ || { __spawn_actor__ } @__actor__ } protected: [ '__spawn_actor__, '__actor__loop__, '__actor__die!__, '__actor__ ] def die! { """ Tells an object to let its actor to die (quit running). """ __actor__die!__ } def actor { """ Returns the Object's actor. If none exists at this moment, a new one will be created and starts running in the background. """ __actor__ } def send_future: message with_params: params ([]) { """ @message Message to be sent as a @FutureSend@. @params @Array@ of parameters of the @FutureSend@. @return @FutureSend@ object that will hold the return value of @message with @params on @self. Creates a @FutureSend@ object (a Future / Promise) that will hold the value of sending @message to @self. """ FutureSend new: __actor__ receiver: self message: message with_params: params } def send_async: message with_params: params ([]) { """ @message Message to be sent asynchronously to @self. @params @Array@ of parameters as part of sending @message asynchronously to @self. @return @nil Sends @message with @params to @self asynchronously and immediately returns @nil. """ __actor__ ! ('async, (message, params), nil) nil } def synchronized: block { """ @block @Block@ to be run only by one Thread at a time. Runs a given @Block@ in a synchronized fashion if called by multiple Threads. Uses a @Mutex@ in the background for synchronization (created on demand for each @Object@). """ @__mutex__ = @__mutex__ || { Mutex new() } @__mutex__ synchronize(&block) } def copy_slots: slots from: object { slots each: |s| { set_slot: s value: (object get_slot: s) } } def get_slots: slots { """ @slots @Array@ of slot names to retrieve from @self. @return @Array@ of slot values of slot names passed in via @slots. """ slots map: |s| { get_slot: s } } def <=> other { """ @other Other object to compare against. @return -1 if @self is smaller, 0 if @self is equal or 1 if @self is greater or equal compared to @other. """ { return -1 } if: (self < other) { return 0 } if: (self == other) return 1 # greater or equal to other } def do: block { """ @block @Block@ to be called in the context of @self. Helper method that calls @block with @self as the receiver. This allows message cascading like code, e.g.: some_complex_object do: { method_1: arg1 method_2: arg2 method_3: arg3 } # this is the same as: some_complex_object method_1: arg1 some_complex_object method_2: arg2 some_complex_object method_3: arg3 """ block call_with_receiver: self } def slots { """ @return @Set@ of slot names that @self has. """ Set new: $ instance_variables map: |s| { s rest to_sym } } def sleep: seconds { """ @seconds Amount of seconds to sleep. Sets the current Thread (in which self is running) for a given amount to sleep. """ Thread sleep: seconds } }