diff --git a/docs/block.md b/docs/block.md new file mode 100644 index 0000000..b1bb60e --- /dev/null +++ b/docs/block.md @@ -0,0 +1,128 @@ +--- +id: block +title: Block +--- + +## Block + +```ruby +def foo(ary: [1, 2, 3]) + ary.each do |s| # start of the block + puts s + end # end of the block +end +``` + +Sentences that are surrounded by `do` and `end` forms a block. Block can take one or more "block variables" surrounded by `| |`. +(`{ }` cannot be used for forming a block.) + +### `Block` class + +A special class to create a block object (anonymous function). You can perform `Block.new`. + +```ruby +b = Block.new do + 100 +end + +b.call #=> 100 + +``` + +Then you can perform `#call` to execute the block in the block object. + +```ruby +def baz + 1000 +end + +class Foo + def exec_block(block) + block.call + end + + def baz + 100 + end +end + +b = Block.new do + baz +end + +f = Foo.new +f.exec_block(b) +``` + +With `Block` class, you can explicitly pass a block (or more blocks) to methods. + +```ruby +b = Block.new do |arg| + arg + 1000 +end + +b.call(49) #=> 1049 + +``` + +`#call` can take arguments that corresponds to the block parameters (`|arg|` above). + +### Special `get_block` keyword + +```ruby +def bar(block) + # runs the block object and the block arg simultaneously + block.call + get_block.call +end + +def foo + bar(get_block) do # passes two blocks to `bar` + 20 + end +end + +foo do + 10 +end +``` + +`get_block` is Goby's original: not a method but a **keyword** to retrive a given block argument as a block object. By this, you can pass around or `call` the given block arguments as block objects. + +### `yield` + +```ruby +def foo + yield(10) # executes the block given +end + +foo do |ten| + ten + 20 +end +``` + +`yield` invokes the given block argument. Not for block object. + +## Closure + +```ruby +count = 0 # the declaration is used +b = Block.new do + count += 1 # the block looks preserving the `count` +end + +class Foo + def bar(blk) + count = 9 # (does not affect) + puts blk.call # local variable is resolved to the one above + end +end + +Foo.new.bar b #=> 1 +Foo.new.bar b #=> 2 +Foo.new.bar b #=> 3 + +``` + +When local variables are declared and then forms a block (such as `Block.new`), the local variable within the block behaves as if they are "preserved" within the block when executed like instance variables of the block object. + +Actually, when the block is executed, the local variables are simply resolved to the ones in the original environment that the block was formed. In other words, such pre-declared local variables within the block has a **lexical scope** (performs static resolutions), and the behavior is called a **closure**. \ No newline at end of file diff --git a/docs/class_and_module.md b/docs/class_and_module.md index acdd7e1..8786685 100644 --- a/docs/class_and_module.md +++ b/docs/class_and_module.md @@ -24,7 +24,7 @@ end ```ruby module Foo - def foo + def foo 99 end end @@ -50,11 +50,11 @@ Baz.bar #=> 88 Modules can be included into other modules or classed via "`#include`", as well as can be used for extending other classes or modules via "`#extend`". -In Goby, "**composition over inheritance**" concept is recommended. +In Goby, "**composition over inheritance**" concept is recommended. ```ruby module Foo - def foo + def foo 99 end end diff --git a/docs/flow_control.md b/docs/flow_control.md index 719da0b..77e3e93 100644 --- a/docs/flow_control.md +++ b/docs/flow_control.md @@ -19,6 +19,7 @@ if foo end bar if foo # Not allowed + ``` Also, Goby also support both else and elsif keywords. @@ -47,6 +48,7 @@ b = if false end puts(b) #=> nil + ``` ## `break` Statement @@ -68,6 +70,7 @@ foo 20 #=> 5 6 7 8 9 #=> ouch! #=> out of the block + ``` ## `case` statement diff --git a/docs/hello-world.md b/docs/hello-world.md new file mode 100644 index 0000000..565a1d3 --- /dev/null +++ b/docs/hello-world.md @@ -0,0 +1,67 @@ +--- +id: hello-world +title: Hello World +sidebar_label: Hello World +--- + +## Hello World + +This "Hello World" represents an ideal coding style in Goby. Note that no inheritance with `<` has been used. + +* Create a file named `hello.gb` with the following code: + +```ruby +class Greet + attr_accessor :audience, :head, :tail + + def initialize + @head = "Hello, " + @tail = "!" + end + + def name + audience.name + end + + def say + puts head + name + tail + end +end + +module MyName + attr_reader :name + + def initialize + @name = self.class.to_s + end +end + +class World + include MyName +end + +greet = Greet.new +greet.audience = World.new +greet.say + +class Goby + include MyName +end + +greet.audience = Goby.new +greet.say +``` + +* Then run: + +```bash +$ goby hello.gb +#=> Hello, World! +#=> Hello, Goby! +``` + +* You can also run such codes interactively via Goby's REPL (grb) by: + +```bash +goby -i +``` \ No newline at end of file diff --git a/docs/method_definition.md b/docs/method_definition.md index a743480..dfdb77c 100644 --- a/docs/method_definition.md +++ b/docs/method_definition.md @@ -11,6 +11,7 @@ def foo_bar(baz) end foo_bar "Hi, Goby!" #=> Hi, Goby! + ``` Method name should be "`[a-z][a-z0-9_]+\??`" (snake_case). You can omit the trailing "`()`" only if no parameters are taken. @@ -37,7 +38,7 @@ Keep parameters **at most around 2** as far as possible to keep interfaces simpl 1. **normal parameters** (like `a`) 2. **normal parameters with default value** (like `a=1`) 3. **optional parameters** (array or hash, like `ary=[]` or `hs={}`) -4. **keyword parameters** (like `kwd:`) +4. **keyword parameters** (like `kwd:`) 5. **keyword parameters with default value** (like `kwd: 1` or `ary: [1,2,3]` or `hsh: {key: "value"}`) 6. **splat parameters** (like `*sp`) @@ -52,6 +53,7 @@ def area(radius) end area 6 #=> 18.84 + ``` A method returns an object from the last-evaluated expression. @@ -60,6 +62,7 @@ A method returns an object from the last-evaluated expression. def area(radius) return radius * PI # not recommended end + ``` `return` keyword is supported, but in most cases it's redundant (methods would return the last value by default). @@ -70,6 +73,7 @@ def my_array end my_array #=> [1, 2, 3] + ``` If you want to return multiple values, you should explicitly use an array literal `[ ]`. Returning unbracketed values like `1, 2, 3` is unsupported. @@ -81,7 +85,7 @@ module Foo def bar puts "bar" end - + def baz(count, email: "goby@example.com") count.times do puts email @@ -113,6 +117,7 @@ end str.foo #=> GobyGoby + ``` You can define **singleton methods** by using `def` keyword and `object.methodname` notation. `self` is to refer to the object itself within the object. @@ -124,7 +129,7 @@ module Foo def self.bar #2 singleton method with `self.` 92 end - + def Foo.bar #3 singleton method with a class name (not recommended) end ``` @@ -141,6 +146,7 @@ def Foo.bar #4 singleton methods outside the Foo end Foo.bar #=> 9999 + ``` You can define singleton methods by using `def ClassName.method_name` or `def ModuleName.method_name`, outside the module/class definition. @@ -187,6 +193,7 @@ String.methods » "string".methods #» ["!=", "*", "+", "<", "<=>", "==", "=~", ">", "[]", "[]=", "capitalize", "chop", "concat", "count", "delete", "downcase", "each_byte", "each_char", "each_line", "empty?", "end_with?", "eql?", "fmt", "include?", "insert", "length", "ljust", "match", "new", "replace", "replace_once", "reverse", "rjust", "size", "slice", "split", "start_with", "strip", "to_a", "to_bytes", "to_d", "to_f", "to_i", "to_s", "upcase", "!", "block_given?", "class", "exit", "instance_eval", "instance_variable_get", "instance_variable_set", "is_a?", "methods", "nil?", "object_id", "puts", "raise", "require", "require_relative", "send", "singleton_class", "sleep", "thread"] + ``` You can call `#methods` against on objects (classes and instances) to show methods. @@ -200,7 +207,7 @@ class Foo def bar 42 end - + def _baz # private method 99 end @@ -219,7 +226,7 @@ class Foo @bar = 42 @baz = 99 end - + def boo _bar = _bar * 2 _baz = _baz + 2 @@ -236,6 +243,7 @@ foo.boo foo.bar # Error foo.baz # Error + ``` You can also make the attribute accessor methods private with `_` for private use. diff --git a/docs/repl.md b/docs/repl.md new file mode 100644 index 0000000..1460a86 --- /dev/null +++ b/docs/repl.md @@ -0,0 +1,166 @@ +--- +id: repl +title: REPL +sidebar_label: REPL +--- + +You can run Goby program interactively via the Goby's REPL (igb) + +## 1. Basic operations + +1. `goby -i` to start REPL. + +* startup massage with version no. and a fortune is shown randomly. +* green prompt `»` are shown. + +```ruby +Goby 0.0.9 😽 😉 🤓 +» +``` + +2. type `help` and hit return to show the following help messages: + +```ruby +» help +commands: + help + reset + exit +» +``` + +The commands above can be auto-completed by hitting Tab key. +See the shortcuts below. + +3. type `reset` and Return key to reset REPL + +```ruby +Restarting Igb... +Goby 0.0.9 😎 😛 😪 +» +``` + +4. type `exit` and Return key to exit REPL + +```ruby +» exit +Bye! +``` + +You can exit by `Ctrl`+`C` on green `»`. + +5. You can suppress echo back by adding a trailing `;` + +```ruby +» 5*7; +» +``` + +6. When entering a block, the heading changes to red `¤`. When finishing a block, the heading gets back to green `»` and then the outputs are shown on the yellow heading `#»`. + +```ruby +» module MyName +¤ attr_reader :name +¤ +¤ def initialize +¤ @name = self.class.to_s +¤ end +» end +#» MyName + +``` + +You can cancel entering the current block by `Ctrl`+`C` on red `¤`. + +```ruby +» module MyName +¤ -- block cleared +» +``` + +7. You can copy the code on REPL with heading `»` or `¤` and paste it to REPL again. The redundant headings are automatically removed. + +```ruby +» module MyName +¤ attr_reader :name +¤ +¤ def initialize +¤ @name = self.class.to_s +¤ end +» end + +# copying the codes with headings above and pasting to REPL removes headings↓ + +» module MyName +¤ attr_reader :name +¤ +¤ def initialize +¤ @name = self.class.to_s +¤ end +» end +``` + +## Shortcuts + +(Based on [readline](https://github.com/chzyer/readline/blob/master/doc/shortcut.md)) + +`Meta`+`B` means press `Esc` and `n` separately. +Users can change that in terminal simulator(i.e. iTerm2) to `Alt`+`B` +Notice: `Meta`+`B` is equals with `Alt`+`B` in windows. + +* Shortcut in normal mode + +| Shortcut | Comment | +| ------------------ | --------------------------------- | +| `Ctrl`+`A` | Beginning of line | +| `Ctrl`+`B` / `←` | Backward one character | +| `Meta`+`B` | Backward one word | +| `Ctrl`+`C` | Exit (or discard the current block)| +| `Ctrl`+`D` | Delete one character | +| `Meta`+`D` | Delete one word | +| `Ctrl`+`E` | End of line | +| `Ctrl`+`F` / `→` | Forward one character | +| `Meta`+`F` | Forward one word | +| `Ctrl`+`G` | Cancel | +| `Ctrl`+`H` | Delete previous character | +| `Ctrl`+`I` / `Tab` | Command line completion | +| `Ctrl`+`J` | Line feed | +| `Ctrl`+`K` | Cut text to the end of line | +| `Ctrl`+`L` | Clear screen | +| `Ctrl`+`M` | Same as Enter key | +| `Ctrl`+`N` / `↓` | Next line (in history) | +| `Ctrl`+`P` / `↑` | Prev line (in history) | +| `Ctrl`+`R` | Search backwards in history | +| `Ctrl`+`S` | Search forwards in history | +| `Ctrl`+`T` | Transpose characters | +| `Meta`+`T` | Transpose words (TODO) | +| `Ctrl`+`U` | Cut text to the beginning of line | +| `Ctrl`+`W` | Cut previous word | +| `Backspace` | Delete previous character | +| `Meta`+`Backspace` | Cut previous word | +| `Enter` | Line feed | + + +* Shortcut in Search Mode (`Ctrl`+`S` or `Ctrl`+`r` to enter this mode) + +| Shortcut | Comment | +| ----------------------- | --------------------------------------- | +| `Ctrl`+`S` | Search forwards in history | +| `Ctrl`+`R` | Search backwards in history | +| `Ctrl`+`C` / `Ctrl`+`G` | Exit Search Mode and revert the history | +| `Backspace` | Delete previous character | +| Other | Exit Search Mode | + +* Shortcut in Complete Select Mode (double `Tab` to enter this mode) + +| Shortcut | Comment | +| ----------------------- | ---------------------------------------- | +| `Ctrl`+`F` | Move Forward | +| `Ctrl`+`B` | Move Backward | +| `Ctrl`+`N` | Move to next line | +| `Ctrl`+`P` | Move to previous line | +| `Ctrl`+`A` | Move to the first candicate in current line | +| `Ctrl`+`E` | Move to the last candicate in current line | +| `Tab` / `Enter` | Use the word on cursor to complete | +| `Ctrl`+`C` / `Ctrl`+`G` | Exit Complete Select Mode | +| Other | Exit Complete Select Mode | \ No newline at end of file diff --git a/docs/terminology.md b/docs/terminology.md new file mode 100644 index 0000000..908210c --- /dev/null +++ b/docs/terminology.md @@ -0,0 +1,50 @@ +--- +id: terminology +title: Terminology +sidebar_label: Terminology +--- + +## Goby terminology + +### A + +* **Argument** (arg): to be used in *method call*. + +### B + +* **Block**: `do`-`end`, `if`-`end`, `case`-`end`. + +### C + +* **Constant**: Constants and class/module names are not the same. The latter can be redefined while the former is not reentrant. +* **Composition**: +* **Composition over inheritance**: A principle of OOPs. One of Goby's motto. + +### D + +* **Duck-typing**: a preferable coding in Goby, as same as in Ruby. + +### G + +* **Go language** (golang): Goby's father and a mentor. + +### M + +* **Metaprogramming**: basically eliminated in Goby. +* **Module method**: actually a singleton method on a module. +* **Monkey patch**: still possible in Goby. + +### P + +* **Parameter** (param): to be used in *method definitions*. +* **Polymorphism**: Preferable coding in Goby, achieved by **duck-typing**. + +### R + +* **Ruby**: Goby's mother. + +### S + +* **Singleton method**: a method only for a specific object. Module methods and class methods are singleton methods. +* **st0012**: Creator of Goby. [https://github.com/st0012](https://github.com/st0012) +* **`super`**: eliminated in Goby. \ No newline at end of file diff --git a/docs/thread_and_channel.md b/docs/thread_and_channel.md index c0f31c7..55e5e86 100644 --- a/docs/thread_and_channel.md +++ b/docs/thread_and_channel.md @@ -51,7 +51,7 @@ puts(i) or ```ruby -i = 0 +i = 0 thread do i += 1 # avoid non-Channel variables for communicating outside end @@ -72,6 +72,7 @@ thread do end puts(c.receive) #=> 10 + ``` And Goby's `Channel` inherits Go channel's blocking behavior, so you can use it to do flow control @@ -107,4 +108,54 @@ thread do end puts(c.receive.bar) #=> 100 + +``` + +### Concurrent array + +```ruby +require 'concurrent/array' +a = Concurrent::Array.new([1, 2 ,3 ,5 , 10]) +a[0] = a[1] + a[2] + a[3] * a[4] ``` + +`Concurrent::Array` is a thread-safe Array class, implemented as a wrapper of an ArrayObject, coupled with an R/W mutex. + +We don't implement `dig` to the class, as it has no concurrency guarantees. + +### Concurrent hash + +```ruby +require 'concurrent/hash' +hash = Concurrent::Hash.new({ "a": 1, "b": 2 }) +hash["a"] # => 1 + +``` + +`Concurrent::Hash` is an implementation of thread-safe associative arrays (Hash). + +The implementation internally uses Go's `sync.Map` type, with some advantages and disadvantages: + +- It is highly performant and predictable for a certain pattern of usage: + - *concurrent loops with keys that are stable over time, and either few steady-state stores, or stores localized to one goroutine per key* +- Performance and predictability in other conditions are unspecified +- Iterations are non-deterministic; during iterations, keys may not be included +- Size can't be retrieved +- For the reasons above, the Hash APIs implemented are minimal + +For details, see https://golang.org/pkg/sync/#Map. + +### Concurrent rw rock + +```ruby +require 'concurrent/rw_lock' +lock = Concurrent::RWLock.new +lock.with_read_lock do + # critical section +end +lock.with_write_lock do + # critical section +end +``` + +`Concurrent::RWLock` is a Readers-Writer Lock (readers can concurrently put a lock, while a writer requires exclusive access). The implementation internally uses Go's `sync.RWLock` type. diff --git a/docs/tips-tricks.md b/docs/tips-tricks.md new file mode 100644 index 0000000..082d26d --- /dev/null +++ b/docs/tips-tricks.md @@ -0,0 +1,31 @@ +--- +id: tips-tricks +title: Tips & Tricks +sidebar_label: Tips & Tricks +--- + +## REPL + +* You can use all the "readline" operations, like pressing `↑` key to go back history. + +* You can copy the code on REPL with heading `»` or `¤` and paste it to REPL again. The redundant headings are automatically removed. + +```ruby +» module MyName +¤ attr_reader :name +¤ +¤ def initialize +¤ @name = self.class.to_s +¤ end +» end + +# copying the codes with headings and pasting to REPL↓ + +» module MyName +¤ attr_reader :name +¤ +¤ def initialize +¤ @name = self.class.to_s +¤ end +» end +``` \ No newline at end of file diff --git a/docs/variable_and_constant.md b/docs/variable_and_constant.md index e7df7f1..31f1ba9 100644 --- a/docs/variable_and_constant.md +++ b/docs/variable_and_constant.md @@ -12,9 +12,48 @@ Current Goby supports only two types of variables: **local** and **instance** va ```ruby foo = "foo" # local variable -@bar = "bar" # instance variable + +``` + +```ruby +module State + def initialize(state) + @state = state # declaring an instance variable by assignment + end + def show + @state # accessible from other instance methods + end +end + +state = State.new "success" +state.show +#=> success + +``` + +### Scope + +* local/instance variables: + - from the line the variable is declared + - to the end of the current **block** or the current **method**/**module**/**class** definition + +```ruby +class Foo + outside = 42 + def bar + outside * 2 + end +end + +Foo.bar +#=> UndefinedMethodError: Undefined Method 'outside' for + ``` +**Note**: declaring instance variables **outside** the method definition, it will become a kind of **singleton class variable**(in Ruby, this is called a confusing "class instance variable") with a very narrow scope (the class itself), thus only accessible from its class methods. + +This is a sort of side effects and is **not** recommended. Keep your declaration of instance variables within the method definitions. + ## Constants Constant's scope is global, and the name should start with an uppercase letter. Use camel-case for Constant names. @@ -23,6 +62,7 @@ Goby's constant has a big difference from the one in Ruby language: Goby's const ```ruby Foo = 10 Foo = 100 #=> ConstantAlreadyInitializedError + ``` Module names and class names are also constants, which can be defined with module and class keywords respectively, thus you can't assign a value to a constant if the name has already been defined as a module or a class. @@ -34,6 +74,7 @@ Foo = 100 #=> ConstantAlreadyInitializedError module Foo; end Foo = 100 #=> ConstantAlreadyInitializedError + ``` Thus constant's declaration has a limitation: except defining classes or modules, you can only define constants to preserve initial values like: @@ -63,6 +104,7 @@ def bar end bar #» ERROR: ConstantAlreadyInitializedError: Constant Const already been initialized. Can't assign value to a constant twice.. At :2 + ``` ## Assignment @@ -98,6 +140,7 @@ a = b = [1, 2] b[0] = 2 puts(b) #=> [2, 2] puts(a) #=> [1, 2] + ``` ### Multi-variable Assignment @@ -108,7 +151,9 @@ Multiple variable assignment is also supported in Goby: a, b = [1, 2] puts(a) #=> 1 puts(b) #=> 2 + ``` + But we only expect the assigned value to be an Array object, which means we do not support something like: ```ruby @@ -121,11 +166,13 @@ And if the number of array's elements are less than the number of variables, tho a, b = [1] puts(a) #=> 1 puts(b) #=> nil + ``` ### Note -We do not support multi-variable assignment and chained assignment for Constant, only for local variable and instance variable +We do not support multi-variable assignment and chained assignment for **Constant**, only for local variable and instance variable. + ### About Return Value In Ruby, assignment will return value if you need them, like chained assignment or assign variable in if statement's condition. Goby also support this feature, so the following use cases are all available in Goby diff --git a/website/sidebars.json b/website/sidebars.json index c0684d5..44fc027 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -2,21 +2,26 @@ "docs": { "Get Startted": [ "introduction", - "installation" + "installation", + "hello-world", + "tips-tricks", + "terminology" ], "Features": [ "plugin-system", "thread-and-channel", "simple-server", "easy-json-rendering", - "load-library-and-files" + "load-library-and-files", + "repl" ], "Language": [ "class-and-module", "variable-and-constant", "method-definition", "method-call", - "flow-control" + "flow-control", + "block" ] } }