Nigel  Uys

Nigel Uys

1680174480

Rust Library for Single Assignment Cells & Lazy Statics without Macros

Overview

once_cell provides two new cell-like types, unsync::OnceCell and sync::OnceCell. OnceCell might store arbitrary non-Copy types, can be assigned to at most once and provide direct access to the stored contents. In a nutshell, API looks roughly like this:

impl OnceCell<T> {
    fn new() -> OnceCell<T> { ... }
    fn set(&self, value: T) -> Result<(), T> { ... }
    fn get(&self) -> Option<&T> { ... }
}

Note that, like with RefCell and Mutex, the set method requires only a shared reference. Because of the single assignment restriction get can return an &T instead of Ref<T> or MutexGuard<T>.

once_cell also has a Lazy<T> type, build on top of OnceCell which provides the same API as the lazy_static! macro, but without using any macros:

use std::{sync::Mutex, collections::HashMap};
use once_cell::sync::Lazy;

static GLOBAL_DATA: Lazy<Mutex<HashMap<i32, String>>> = Lazy::new(|| {
    let mut m = HashMap::new();
    m.insert(13, "Spica".to_string());
    m.insert(74, "Hoyten".to_string());
    Mutex::new(m)
});

fn main() {
    println!("{:?}", GLOBAL_DATA.lock().unwrap());
}

More patterns and use-cases are in the docs!

Related crates

The API of once_cell is being proposed for inclusion in std.


Download Details:

Author: Matklad
Source Code: https://github.com/matklad/once_cell 
License: Apache-2.0, MIT licenses found

#rust #evaluate #macro 

Rust Library for Single Assignment Cells & Lazy Statics without Macros
Gordon  Murray

Gordon Murray

1670675543

How to Reduce Boilerplate Code With Scala Macros and Quasiquotes

The concise syntax of Scala usually helps developers avoid writing boilerplate. When repetitive code is required anyway, developers can use macros and quasiquotes to keep code clean and maintainable. Here’s how.

The Scala language offers developers the opportunity to write object-oriented and functional code in a clean and concise syntax (as compared to Java, for example). Case classes, higher-order functions, and type inference are some of the features that Scala developers can leverage to write code that’s easier to maintain and less error-prone.

Unfortunately, Scala code is not immune to boilerplate, and developers may struggle to find a way to refactor and reuse such code. For example, some libraries force developers to repeat themselves by calling an API for each subclass of a sealed class.

But that’s only true until developers learn how to leverage macros and quasiquotes to generate the repeated code at compile time.

Use Case: Registering the Same Handler for All Subtypes of a Parent Class

During the development of a microservices system, I wanted to register a single handler for all events derived from a certain class. To avoid distracting us with the specifics of the framework I was using, here’s a simplified definition of its API for registering event handlers:

trait EventProcessor[Event] {
  def addHandler[E <: Event: ClassTag](
      handler: E => Unit
  ): EventProcessor[Event]

  def process(event: Event)
}

Having an event processor for any Event type, we can register handlers for subclasses of Event with the addHandler method.

Looking at the above signature, a developer might expect a handler registered for a given type to be invoked for events of its subtypes. For example, let’s consider the following class hierarchy of events involved in the User entity lifecycle:

 

Hierarchy of Scala events descending from UserEvent. There are three direct descendants: UserCreated (having a name and email, which are both Strings), UserChanged, and UserDeleted. Furthermore, UserChanged has two descendants of its own: NameChanged (having a name, which is a string) and EmailChanged (having an email, which is a string).

A Scala event class hierarchy.

 

The corresponding Scala declarations look like this:

sealed trait UserEvent
final case class UserCreated(name: String, email: String) extends UserEvent
sealed trait UserChanged                                  extends UserEvent
final case class NameChanged(name: String)                extends UserChanged
final case class EmailChanged(email: String)              extends UserChanged
case object UserDeleted                                   extends UserEvent

We can register a handler for each specific event class. But what if we want to register a handler for all the event classes? My first attempt was to register the handler for the UserEvent class. I expected it to be invoked for all the events.

val handler   = new EventHandlerImpl[UserEvent]
val processor = EventProcessor[UserEvent].addHandler[UserEvent](handler)

I noticed that the handler was never invoked during the tests. I dug into the code of Lagom, the framework I was using.

I found that the event processor implementation stored the handlers in a map with the registered class as the key. When an event is emitted, it looks for its class in that map to get the handler to call. The event processor is implemented along these lines:

type Handler[Event] = (_ <: Event) => Unit

private case class EventProcessorImpl[Event](
    handlers: Map[Class[_ <: Event], List[Handler[Event]]] =
      Map[Class[_ <: Event], List[Handler[Event]]]()
) extends EventProcessor[Event] {

  override def addHandler[E <: Event: ClassTag](
      handler: E => Unit
  ): EventProcessor[Event] = {
    val eventClass =
      implicitly[ClassTag[E]].runtimeClass.asInstanceOf[Class[_ <: Event]]
    val eventHandlers = handler
      .asInstanceOf[Handler[Event]] :: handlers.getOrElse(eventClass, List())
    copy(handlers + (eventClass -> eventHandlers))
  }

  override def process(event: Event): Unit = {
    handlers
      .get(event.getClass)
      .foreach(_.foreach(_.asInstanceOf[Event => Unit].apply(event)))
  }
}

Above, we registered a handler for the UserEvent class, but whenever a derived event like UserCreated was emitted, the processor wouldn’t find its class in the registry.

Thus Begins the Boilerplate Code

The solution is to register the same handler for each concrete event class. We can do it like this:

val handler = new EventHandlerImpl[UserEvent]  
val processor = EventProcessor[UserEvent]  
  .addHandler[UserCreated](handler)  
  .addHandler[NameChanged](handler)  
  .addHandler[EmailChanged](handler)  
  .addHandler[UserDeleted.type](handler)

Now the code works! But it’s repetitive.

It’s also difficult to maintain, as we will need to modify it every time we introduce a new event type. We might also have other places in our codebase where we are forced to list all the concrete types. We would also need to make sure to modify those places.

This is disappointing, as UserEvent is a sealed class, meaning that all its direct subclasses are known at compile time. What if we could leverage that information to avoid boilerplate?

Macros to the Rescue

Normally, Scala functions return a value based on the parameters we pass to them at run time. You can think of Scala macros as special functions that generate some code at compile time to replace their invocations with.

While the macro interface might seem to take values as parameters, its implementation will actually capture the abstract syntax tree (AST)—the internal representation of source code structure that the compiler uses—of those parameters. It then uses the AST to generate a new AST. Finally, the new AST replaces the macro call at compile time.

Let’s look at a macro declaration that will generate event handler registration for all the known subclasses of a given class:

def addHandlers[Event](
      processor: EventProcessor[Event],
      handler: Event => Unit
  ): EventProcessor[Event] = macro setEventHandlers_impl[Event]  
  
  
def setEventHandlers_impl[Event: c.WeakTypeTag](c: Context)(
      processor: c.Expr[EventProcessor[Event]],
      handler: c.Expr[Event => Unit]
  ): c.Expr[EventProcessor[Event]] = {

  // implementation here
}

Notice that for each parameter (including type parameter and return type), the implementation method has a corresponding AST expression as a parameter. For example, c.Expr[EventProcessor[Event]] matches EventProcessor[Event]. The parameter c: Context wraps the compilation context. We can use it to get all the information available at compile time.

In our case, we want to retrieve the children of our sealed class:

import c.universe._  
  
val symbol = weakTypeOf[Event].typeSymbol

def subclasses(symbol: Symbol): List[Symbol] = {  
  val children = symbol.asClass.knownDirectSubclasses.toList  
  symbol :: children.flatMap(subclasses(_))  
}  
  
val children = subclasses(symbol)

Note the recursive call to the subclasses method to ensure that indirect subclasses are also processed.

Now that we have the list of the event classes to register, we can build the AST for the code that the Scala macro will generate.

Generating Scala Code: ASTs or Quasiquotes?

To build our AST, we can either manipulate AST classes or use Scala quasiquotes. Using AST classes can produce code that is difficult to read and maintain. In contrast, quasiquotes dramatically reduce the complexity of the code by allowing us to use a syntax that is very similar to the generated code.

To illustrate the simplicity gain, let’s take the simple expression a + 2. Generating this with AST classes looks like this:

val exp = Apply(Select(Ident(TermName("a")), TermName("$plus")), List(Literal(Constant(2))))

We can achieve the same with quasiquotes with a more concise and readable syntax:

val exp = q"a + 2"

To keep our macro straightforward, we’ll use quasiquotes.

Let’s create the AST and return it as the result of the macro function:

val calls = children.foldLeft(q"$processor")((current, ref) =>
  q"$current.addHandler[$ref]($handler)"
)
c.Expr[EventProcessor[Event]](calls)

The code above starts with the processor expression received as a parameter, and for each Event subclass, it generates a call to the addHandler method with the subclass and handler function as parameters.

Now we can call the macro on the UserEvent class and it will generate the code to register the handler for all the subclasses:

val handler = new EventHandlerImpl[UserEvent]  
val processor = EventProcessorMacro.addHandlers(EventProcessor[UserEvent],handler)

That will generate this code:

com.example.event.processor.EventProcessor
.apply[com.example.event.handler.UserEvent]()
.addHandler[UserEvent](handler)
.addHandler[UserCreated](handler)
.addHandler[UserChanged](handler)
.addHandler[NameChanged](handler)
.addHandler[EmailChanged](handler)
.addHandler[UserDeleted](handler)

The code of the complete project compiles correctly and the test cases demonstrate that the handler is indeed registered for each subclass of UserEvent. Now we can be more confident in the capacity of our code to handle new event types.

Repetitive Code? Get Scala Macros to Write It

Even though Scala has a concise syntax that usually helps to avoid boilerplate, developers can still find situations where code becomes repetitive and cannot be easily refactored for reuse. Scala macros can be used with quasiquotes to overcome such issues, keeping Scala code clean and maintainable.

There are also popular libraries, like Macwire, that leverage Scala macros to help developers generate code. I strongly encourage every Scala developer to learn more about this language feature, as it can be a valuable asset in your tool set.

Original article source at: https://www.toptal.com/

#scala #macro 

How to Reduce Boilerplate Code With Scala Macros and Quasiquotes

Unroll.jl: Julia Macro for Unrolling For-loops

Unroll macro

This package provides the unroll and tuplegen macros. The unroll macro in Julia unrolls simple for-loops. For example, the following code:

@unroll for i = 1 : 2
   x += a[i]
end

will macro-expand as:

x += a[1]
x += a[2]

For this to be possible, the loop bounds must be known at the time of macro-expansion. A common case is that they are literal constant values as in the above example. The loop bounds may include symbolic constants that are global within the module:

const LOOPBOUND = 2
function myfunct()
   @unroll for i = 1 : LOOPBOUND
      <etc>
   end
end

The unroll macro can be nested.

Finally, the unroll macro will search for conditionals that depend on the loop counter and unroll these as well. For example, the call:

@unroll for i = 1 : 4
    if mod(i,2) == 1
        a += b[i]
    else
        a += 2*b[i]
    end
 end

will macro-expand to:

a += b[1]
a += 2*b[2]
a += b[3]
a += 2*b[4]

The tuplegen macro

The tuplegen macro generates fixed-length tuples using comprehension-like syntax. For example:

v = @tuplegen [(i==2)? i * 6 : i for i = 1 : 4]

macro-expands to:

v = (1, 2*6, 3, 4)

and therefore generates the tuple (1,12,3,4). Without the @tuplegen call, this same statement would generate the array [1,12,3,4]. It is possible generate tuples from comprehensions via the following standard statement:

v = tuple([(i==2)? i * 6 : i for i = 1 : 4]...)

but this statement is less efficient because it creates a heap-allocated array as a temporary.

Here is a more complicated example of @tuplegen. Suppose 2-by-2 matrices are represented as 2-tuples of 2-tuples, e.g., ((1,2),(5,7)) stands for:

1  2
5  7

Then 2-by-2 matrix multiplication may be defined by:

mtxmult(a,b) = @tuplegen [@tuplegen [a[i][1]*b[1][j] + a[i][2]*b[2][j]
                                     for j = 1 : 2]
                          for i = 1 : 2]

This definition generates unrolls into four expressions on the right-hand side and works as expected:

julia> mtxmult(((1,2),(5,7)),((4,1),(2,8)))
((8,17),(34,61))

As with the @unroll macro, the loop bounds for @tuplegen must be known at macro-expansion time. In particular, the following plausible attempt to define a generic function for addition of arbitrary fixed-length tuples (so that (1,7)+(-2,3) yields (-1,10)) does not work:

+{N}(a::NTuple{N}, b::NTuple{N}) = @tuplegen [a[i]+b[i] for i=1:N]

because the type parameter N is not known at the time of macro expansion; instead it is determined later by the dispatch mechanism. If someone knows how to fix this, please create an issue or pull request. (It is possible to write generic addition for tuples via the more complicated generated-function mechanism.)

Cautionary notes

  • The loop index must be a simple variable (e.g., the loop cannot be of the form for (k,v) in mydict or something similar).
  • The loop index is matched symbolically by the macro. This means that the same symbol may not be used in the loop body with a different meaning (e.g., qualified by a different module name).
  • If the loop index is somehow concealed inside the loop body, say with an eval/parse statement, then the macro will fail.
  • The macro calls eval to obtain the loop bounds and also to check whether if conditions are satisfied. This means that the loop should not include statements with side effects (like print) in either the loop bounds or in conditionals, since these statements may get unexpectedly executed during the macro expansion phase.

Download Details:

Author: StephenVavasis
Source Code: https://github.com/StephenVavasis/Unroll.jl 
License: MIT license

#julia #loops #macro 

Unroll.jl: Julia Macro for Unrolling For-loops

Naïve Combined Subexpression Elimination in Julia

CommonSubexpressions.jl

This Julia package provides the @cse macro, which performs common subexpression elimination. That means that, given a piece of code like:

for i in 1:10
    x[i] = foo(1) + i
end

in which the function foo(1) is evaluated 10 times, the @cse macro will produce code that moves that expression out of the loop:

foo_1 = foo(1)
for i in 1:10
    x[i] = foo_1 + i
end

and thus only evaluates foo(1) once.

Arbitrarily complex nested expressions can be handled, and should result in more efficient code:

@cse inv(H) * (G + W) - (G + W)' * inv(H)

becomes:

inv_H = inv(H)
G_plus_W = G + W
inv_H * G_plus_W - G_plus_W' * inv_H

You can also wrap entire function definitions or code blocks:

@cse function foo(x)
    [f(x) == i for i in 1:5]
end

Caveats

This package is very new and its results may not be correct. Please use it carefully and report any issues you find.

Any function called within a block wrapped in the @cse macro must be pure. That is to say, the function must have no side-effects. The @cse macro can not enforce or verify this. If your function has side-effects, then the common subexpression elimination may change the behavior of your program, since those side-effects will not happen as often as you had expected.

Brief aside on function purity

A pure function is one with no side-effects. When we say that a function has side-effects, we mean that calling it somehow changes the state of your program, beyond just the value that it returns. A trivial function that does have a side-effect is:

f_counter = 0
function f(x)
    global f_counter
    f_counter += 1
    2 * x
end

which increases a counter f_counter every time it is called.

In addition, any function that mutates its input arguments can not be pure, since changing its input arguments constitutes a side effect.

Visualization

The CSE transformation can be visualized using the TreeView.jl package. Here's a very simple example:

rendering of before and after as TreeView.jl trees

How it Works

This package does not (currently) construct a full data-flow graph like DataFlow.jl. Instead, it performs a few relatively simple steps:

  1. Initialize the set of disqualified symbols to {}
  2. Initialize the list of setup commands to []
  3. Walk the expression tree, repeatedly performing these steps:
    1. If an assignment operation (like x = 5) is encountered, then add the target of the assignment (x in this case) to the disqualified symbols.
    2. If a function call is encountered and all the function arguments are either constants or symbols, and those symbols are not disqualified, then:
      1. Replace the function call in the current expression with a newly generated symbol
      2. Append to the setup commands an expression which performs the function call and assigns it to the new symbol
  4. Return the transformed expression, with all the setup commands prepended.

This simple procedure ensures that we only cache functions whose inputs do not change within the given code block (assuming that all function calls are pure, as required above).

Download Details:

Author: rdeits
Source Code: https://github.com/rdeits/CommonSubexpressions.jl 
License: View license

#julia #macro 

Naïve Combined Subexpression Elimination in Julia

Memoize.jl: @memoize Macro for Julia

Memoize.jl

Easy memoization for Julia.

Usage

using Memoize
@memoize function x(a)
    println("Running")
    2a
end
julia> x(1)
Running
2

julia> memoize_cache(x)
IdDict{Any,Any} with 1 entry:
  (1,) => 2

julia> x(1)
2

julia> empty!(memoize_cache(x))
IdDict{Any,Any}()

julia> x(1)
Running
2

julia> x(1)
2

By default, Memoize.jl uses an IdDict as a cache, but it's also possible to specify the type of the cache. If you want to cache vectors based on the values they contain, you probably want this:

using Memoize
@memoize Dict function x(a)
    println("Running")
    a
end

You can also specify the full function call for constructing the dictionary. For example, to use LRUCache.jl:

using Memoize
using LRUCache
@memoize LRU{Tuple{Any,Any},Any}(maxsize=2) function x(a, b)
    println("Running")
    a + b
end
julia> x(1,2)
Running
3

julia> x(1,2)
3

julia> x(2,2)
Running
4

julia> x(2,3)
Running
5

julia> x(1,2)
Running
3

julia> x(2,3)
5

Notes

Note that the @memoize macro treats the type argument differently depending on its syntactical form: in the expression

@memoize CacheType function x(a, b)
    # ...
end

the expression CacheType must be either a non-function-call that evaluates to a type, or a function call that evaluates to an instance of the desired cache type. Either way, the methods Base.get! and Base.empty! must be defined for the supplied cache type.

Download Details:

Author: JuliaCollections
Source Code: https://github.com/JuliaCollections/Memoize.jl 
License: View license

#julia #macro 

Memoize.jl: @memoize Macro for Julia

Convenient Macros for in-place Matrix Operations in Julia

InplaceOps.jl 

InplaceOps.jl is a Julia package that provides macros that enable a simple syntax for performing in-place (i.e. overwriting) array operations using standard arithmetic operators.

Usage

InplaceOps.jl provides a macro @! which rewrites expressions of the form:

  • C = A*B to mul!(C,A,B)
  • C = C*B or C *= B to rmul!(C,B)
  • C = A*C to lmul!(A,B)
  • C = A/B to rdiv!(C,A,B)
  • C = C/B or C /= B to rdiv!(C,B)
  • C = A\B to ldiv!(C,A,B)
  • C = A\C to ldiv!(A,B)

Functionality for broadcasting is no longer supported. Use the Base @. macro instead.

Example

julia> using LinearAlgebra, InplaceOps

julia> T = UpperTriangular(ones(5,5))
5×5 UpperTriangular{Float64,Array{Float64,2}}:
 1.0  1.0  1.0  1.0  1.0
  ⋅   1.0  1.0  1.0  1.0
  ⋅    ⋅   1.0  1.0  1.0
  ⋅    ⋅    ⋅   1.0  1.0
  ⋅    ⋅    ⋅    ⋅   1.0

julia> x_orig = x = [1.0,2.0,3.0,4.0,5.0]
5-element Array{Float64,1}:
 1.0
 2.0
 3.0
 4.0
 5.0

julia> @! x = T \ x
5-element Array{Float64,1}:
 -1.0
 -1.0
 -1.0
 -1.0
  5.0

julia> x === x_orig
true

Download Details:

Author: Simonbyrne
Source Code: https://github.com/simonbyrne/InplaceOps.jl 
License: View license

#julia #macro 

Convenient Macros for in-place Matrix Operations in Julia

Julia package for deconstructing dispatch on NamedTuples

EponymTuples

Julia package for deconstructing dispatch on NamedTuples.

Uses the variable names both for the NamedTuple and deconstruction.

Allows replacing

f((a, b)::NamedTuple{(:a, :b), <: Tuple{Any, Int}}) = ...

(a = a, b = b, c = 3)

with

f(@eponymargs(a, b::Int)) = ...

@eponymtuple(a, b, c = 3)

It is pretty lightweight: @eponymargs and @eponymtuple are the only symbols exported; and the package has no dependencies.

The package is registered, install with

pkg> add EponymTuples

Download Details:

Author: Tpapp
Source Code: https://github.com/tpapp/EponymTuples.jl 
License: View license

#julia #macro 

Julia package for deconstructing dispatch on NamedTuples

UnPack.jl: `@pack!` and `@unpack` Macros

UnPack

It is often convenient to unpack some or all of the fields of a type, and pack, in the case of mutable datatypes (for immutables use Setfield.jl). This is often the case when a struct is passed into a function.

The @unpack and @pack! macros work to unpack types, modules, and dictionaries (and can be customized for other types too, see next section).

using UnPack

mutable struct Para
    a::Float64
    b::Int
end

function f!(var, pa::Para)
    @unpack a, b = pa # equivalent to: a,b = pa.a,pa.b
    out = var + a + b
    b = 77
    @pack! pa = b # equivalent to: pa.b = b
    return out, pa
end

out, pa = f!(7, Para(1,2)) # -> 10.0, Para(1.0, 77)

Example with a dictionary:

d = Dict{Symbol,Any}(:a=>5.0, :b=>2, :c=>"Hi!")
@unpack a, c = d
a == 5.0 #true
c == "Hi!" #true

d = Dict{String,Any}()
@pack! d = a, c
d # -> Dict{String,Any}("a"=>5.0,"c"=>"Hi!")

Customization of @unpack and @pack!

What happens during the (un-)packing of a particular datatype is determined by the functions UnPack.unpack and UnPack.pack!.

The UnPack.unpack function is invoked to unpack one entity of some DataType and has signature:

unpack(dt::Any, ::Val{property}) -> value of property

Note that unpack (and pack!) works with Base.getproperty. By default this means that all the fields of a type are unpacked but if getproperty is overloaded, then it will unpack accordingly.

Three method definitions are included in the package to unpack a composite type/module/NamedTuple, or a dictionary with Symbol or string keys:

@inline unpack(x, ::Val{f}) where {f} = getproperty(x, f)
@inline unpack(x::AbstractDict{Symbol}, ::Val{k}) where {k} = x[k]
@inline unpack(x::AbstractDict{<:AbstractString}, ::Val{k}) where {k} = x[string(k)]

The UnPack.pack! function is invoked to pack one entity into some DataType and has signature:

pack!(dt::Any, ::Val{field}, value) -> value

Three definitions are included in the package to pack into a mutable composite type or into a dictionary with Symbol or string keys:

@inline pack!(x, ::Val{f}, val) where {f} = setproperty!(x, f, val)
@inline pack!(x::AbstractDict{Symbol}, ::Val{k}, val) where {k} = x[k]=val
@inline pack!(x::AbstractDict{<:AbstractString}, ::Val{k}, val) where {k} = x[string(k)]=val

More methods can be added to unpack and pack! to allow for specialized unpacking/packing of datatypes. Here is a MWE of customizing unpack, so that it multiplies the values by 2:

using UnPack
struct Foo
    a
    b
end
p = Foo(1, 2)
@unpack a, b = p
a, b # gives (1, 2)

# Now we specialize unpack for our custom type, `Foo`
@inline UnPack.unpack(x::Foo, ::Val{f}) where {f} = 2 * getproperty(x, f)
@unpack a, b = p
a, b # now gives (2, 4)

Related

Download Details:

Author: Mauro3
Source Code: https://github.com/mauro3/UnPack.jl 
License: MIT license

#julia #macro 

UnPack.jl: `@pack!` and `@unpack` Macros
Rupert  Beatty

Rupert Beatty

1658290740

Laravel-collection-macros: A Set Of Useful Laravel Collection Macros

Laravel-collection-macros

A set of useful Laravel collection macros

This repository contains some useful collection macros.

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Installation

You can pull in the package via composer:

composer require spatie/laravel-collection-macros

The package will automatically register itself.

Macros

after

Get the next item from the collection.

$collection = collect([1,2,3]);

$currentItem = 2;

$currentItem = $collection->after($currentItem); // return 3;
$collection->after($currentItem); // return null;

$currentItem = $collection->after(function($item) {
    return $item > 1;
}); // return 3;

You can also pass a second parameter to be used as a fallback.

$collection = collect([1,2,3]);

$currentItem = 3;

$collection->after($currentItem, $collection->first()); // return 1;

at

Retrieve an item at an index.

$data = new Collection([1, 2, 3]);

$data->at(0); // 1
$data->at(1); // 2
$data->at(-1); // 3

second

Retrieve item at the second index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->second(); // 2

third

Retrieve item at the third index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->third(); // 3

fourth

Retrieve item at the fourth index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->fourth(); // 4

fifth

Retrieve item at the fifth index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->fifth(); // 5

sixth

Retrieve item at the sixth index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->sixth(); // 6

seventh

Retrieve item at the seventh index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->seventh(); // 7

eighth

Retrieve item at the eighth index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->eighth(); // 8

ninth

Retrieve item at the ninth index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->ninth(); // 9

tenth

Retrieve item at the tenth index.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

$data->tenth(); // 10

getNth

Retrieve item at the nth item.

$data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);

$data->getNth(11); // 11

before

Get the previous item from the collection.

$collection = collect([1,2,3]);

$currentItem = 2;

$currentItem = $collection->before($currentItem); // return 1;
$collection->before($currentItem); // return null;

$currentItem = $collection->before(function($item) {
    return $item > 2;
}); // return 2;

You can also pass a second parameter to be used as a fallback.

$collection = collect([1,2,3]);

$currentItem = 1;

$collection->before($currentItem, $collection->last()); // return 3;

catch

See Try

chunkBy

Chunks the values from a collection into groups as long the given callback is true. If the optional parameter $preserveKeys as true is passed, it will preserve the original keys.

collect(['A', 'A', 'B', 'A'])->chunkBy(function($item) {
    return $item == 'A';
}); // return Collection([['A', 'A'],['B'], ['A']])

collectBy

Get an item at a given key, and collect it.

$collection = collect([
    'foo' => [1, 2, 3],
    'bar' => [4, 5, 6],
]);

$collection->collectBy('foo'); // Collection([1, 2, 3])

You can also pass a second parameter to be used as a fallback.

$collection = collect([
    'foo' => [1, 2, 3],
    'bar' => [4, 5, 6],
]);

$collection->collectBy('baz', ['Nope']); // Collection(['Nope'])

eachCons

Get the following consecutive neighbours in a collection from a given chunk size. If the optional parameter $preserveKeys as true is passed, it will preserve the original keys.

collect([1, 2, 3, 4])->eachCons(2); // return collect([[1, 2], [2, 3], [3, 4]])

extract

Extract keys from a collection. This is very similar to only, with two key differences:

  • extract returns an array of values, not an associative array
  • If a value doesn't exist, it will fill the value with null instead of omitting it

extract is useful when using PHP 7.1 short list() syntax.

[$name, $role] = collect($user)->extract('name', 'role.name');

filterMap

Map a collection and remove falsy values in one go.

$collection = collect([1, 2, 3, 4, 5, 6])->filterMap(function ($number) {
    $quotient = $number / 3;

    return is_integer($quotient) ? $quotient : null;
});

$collection->toArray(); // returns [1, 2]

firstOrFail

Get the first item. Throws Spatie\CollectionMacros\Exceptions\CollectionItemNotFound if the item was not found.

$collection = collect([1, 2, 3, 4, 5, 6])->firstOrFail();

$collection->toArray(); // returns [1]

collect([])->firstOrFail(); // throws Spatie\CollectionMacros\Exceptions\CollectionItemNotFound

firstOrPush

Retrieve the first item using the callable given as the first parameter. If no value exists, push the value of the second parameter into the collection. You can pass a callable as the second parameter.

This method is really useful when dealing with cached class properties, where you want to store a value retrieved from an API or computationally expensive function in a collection to be used multiple times.

$collection = collect([1, 2, 3])->firstOrPush(fn($item) => $item === 4, 4);

$collection->toArray(); // returns [1, 2, 3, 4]

Occasionally, you'll want to specify the target collection to be pushed to. You may pass this as a third parameter.

$collection = collect([1, 2, 3]);
$collection->filter()->firstOrPush(fn($item) => $item === 4, 4, $collection);

$collection->toArray(); // returns [1, 2, 3, 4]

fromPairs

Transform a collection into an associative array form collection item.

$collection = collect([['a', 'b'], ['c', 'd'], ['e', 'f']])->fromPairs();

$collection->toArray(); // returns ['a' => 'b', 'c' => 'd', 'e' => 'f']

glob

Returns a collection of a glob() result.

Collection::glob('config/*.php');

groupByModel

Similar to groupBy, but groups the collection by an Eloquent model. Since the key is an object instead of an integer or string, the results are divided into separate arrays.

$posts->groupByModel('category');

// [
//     [$categoryA, [/*...$posts*/]],
//     [$categoryB, [/*...$posts*/]],
// ];

Full signature: groupByModel($callback, $preserveKeys, $modelKey, $itemsKey)

head

Retrieves first item from the collection.

$collection = collect([1,2,3]);

$collection->head(); // return 1

$collection = collect([]);

$collection->head(); // return null

if

The if macro can help branch collection chains. This is the signature of this macro:

if(mixed $if, mixed $then = null, mixed $else = null): mixed

$if, $then and $else can be any type. If a closure is passed to any of these parameters, then that closure will be executed and the macro will use its results.

When $if returns a truthy value, then $then will be returned, otherwise $else will be returned.

Here are some examples:

collect()->if(true, then: true, else: false); // returns true
collect()->if(false, then: true, else: false); // returns false

When a closure is passed to $if, $then or $else, the entire collection will be passed as an argument to that closure.

// the `then` closure will be executed
// the first element of the returned collection now contains "THIS IS THE VALUE"
$collection = collect(['this is a value'])
    ->if(
        fn(Collection $collection) => $collection->contains('this is a value'),
        then: fn(Collection $collection) => $collection->map(fn(string $item) => strtoupper($item)),
        else: fn(Collection $collection) => $collection->map(fn(string $item) => Str::kebab($item))
    );

// the `else` closure will be executed
// the first element of the returned collection now contains "this-is-another-value"
$collection = collect(['this is another value'])
    ->if(
        fn(Collection $collection) => $collection->contains('this is a value'),
        then: fn(Collection $collection) => $collection->map(fn(string $item) => strtoupper($item)),
        else: fn(Collection $collection) => $collection->map(fn(string $item) => Str::kebab($item))
    );

ifAny

Executes the passed callable if the collection isn't empty. The entire collection will be returned.

collect()->ifAny(function(Collection $collection) { // empty collection so this won't get called
   echo 'Hello';
});

collect([1, 2, 3])->ifAny(function(Collection $collection) { // non-empty collection so this will get called
   echo 'Hello';
});

ifEmpty

Executes the passed callable if the collection is empty. The entire collection will be returned.

collect()->ifEmpty(function(Collection $collection) { // empty collection so this will called
   echo 'Hello';
});

collect([1, 2, 3])->ifEmpty(function(Collection $collection) { // non-empty collection so this won't get called
   echo 'Hello';
});

insertAfter

Inserts an item after the first occurrence of a given item and returns the updated Collection instance. Optionally a key can be given.

collect(['zero', 'two', 'three'])->insertAfter('zero', 'one');
// Collection contains ['zero', 'one', 'two', 'three']

collect(['zero' => 0, 'two' => 2, 'three' => 3]->insertAfter(0, 5, 'five');
// Collection contains ['zero' => 0, 'five' => 5, 'two' => 2, 'three' => 3]

insertAfterKey

Inserts an item after a given key and returns the updated Collection instance. Optionally a key for the new item can be given.

collect(['zero', 'two', 'three'])->insertAfterKey(0, 'one');
// Collection contains ['zero', 'one', 'two', 'three']

collect(['zero' => 0, 'two' => 2, 'three' => 3]->insertAfterKey('zero', 5, 'five');
// Collection contains ['zero' => 0, 'five' => 5, 'two' => 2, 'three' => 3]

insertAt

Inserts an item at a given index and returns the updated Collection instance. Optionally a key can be given.

collect(['zero', 'two', 'three'])->insertAt(1, 'one');
// Collection contains ['zero', 'one', 'two', 'three']

collect(['zero' => 0, 'two' => 2, 'three' => 3]->insertAt(1, 5, 'five');
// Collection contains ['zero' => 0, 'five' => 5, 'two' => 2, 'three' => 3]

insertBefore

Inserts an item before the first occurrence of a given item and returns the updated Collection instance. Optionally a key can be given.

collect(['zero', 'two', 'three'])->insertBefore('two', 'one');
// Collection contains ['zero', 'one', 'two', 'three']

collect(['zero' => 0, 'two' => 2, 'three' => 3]->insertBefore(2, 5, 'five');
// Collection contains ['zero' => 0, 'five' => 5, 'two' => 2, 'three' => 3]

insertBeforeKey

Inserts an item before a given key and returns the updated Collection instance. Optionally a key for the new item can be given.

collect(['zero', 'two', 'three'])->insertBeforeKey(1, 'one');
// Collection contains ['zero', 'one', 'two', 'three']

collect(['zero' => 0, 'two' => 2, 'three' => 3]->insertBeforeKey('two', 5, 'five');
// Collection contains ['zero' => 0, 'five' => 5, 'two' => 2, 'three' => 3]

none

Checks whether a collection doesn't contain any occurrences of a given item, key-value pair, or passing truth test. The function accepts the same parameters as the contains collection method.

collect(['foo'])->none('bar'); // returns true
collect(['foo'])->none('foo'); // returns false

collect([['name' => 'foo']])->none('name', 'bar'); // returns true
collect([['name' => 'foo']])->none('name', 'foo'); // returns false

collect(['name' => 'foo'])->none(function ($key, $value) {
   return $key === 'name' && $value === 'bar';
}); // returns true

paginate

Create a LengthAwarePaginator instance for the items in the collection.

collect($posts)->paginate(5);

This paginates the contents of $posts with 5 items per page. paginate accepts quite some options, head over to the Laravel docs for an in-depth guide.

paginate(int $perPage = 15, string $pageName = 'page', int $page = null, int $total = null, array $options = [])

parallelMap

Identical to map but each item in the collection will be processed in parallel. Before using this macro you should pull in the amphp/parallel-functions package.

composer require amphp/parallel-functions

Be aware that under the hood some overhead is introduced to make the parallel processing possible. When your $callable is only a simple operation it's probably better to use map instead. Also keep in mind that parallelMap can be memory intensive.

$pageSources = collect($urls)->parallelMap(function($url) {
    return file_get_contents($url);
});

The page contents of the given $urls will be fetched at the same time. The underlying amp sets a maximum of 32 concurrent processes by default.

There is a second (optional) parameter, through which you can define a custom parallel processing pool. It looks like this:

use Amp\Parallel\Worker\DefaultPool;

$pool = new DefaultPool(8);

$pageSources = collect($urls)->parallelMap(function($url) {
    return file_get_contents($url);
}, $pool);

If you don't need to extend the worker pool, or can't be bothered creating the new pool yourself; you can use an integer the the number of workers you'd like to use. A new DefaultPool will be created for you:

$pageSources = collect($urls)->parallelMap(function($url) {
    return file_get_contents($url);
}, 8);

This helps to reduce the memory overhead, as the default worker pool limit is 32 (as defined in amphp/parallel). Using fewer worker threads can significantly reduce memory and processing overhead, in many cases. Benchmark and customise the worker thread limit to suit your particular use-case.

path

Returns an item from the collection with multidimensional data using "dot" notation. Works the same way as native Collection's pull method, but without removing an item from the collection.

$collection = new Collection([
    'foo' => [
        'bar' => [
            'baz' => 'value',
        ]
    ]
]);

$collection->path('foo.bar.baz') // 'value'

pluckMany

Returns a collection with only the specified keys.

$collection = collect([
    ['a' => 1, 'b' => 10, 'c' => 100],
    ['a' => 2, 'b' => 20, 'c' => 200],
]);

$collection->pluckMany(['a', 'b']);

// returns
// collect([
//     ['a' => 1, 'b' => 10],
//     ['a' => 2, 'b' => 20],
// ]);

pluckToArray

Returns array of values of a given key.

$collection = collect([
    ['a' => 1, 'b' => 10],
    ['a' => 2, 'b' => 20],
    ['a' => 3, 'b' => 30]
]);

$collection->pluckToArray('a'); // returns [1, 2, 3]

prioritize

Move elements to the start of the collection.

$collection = collect([
    ['id' => 1],
    ['id' => 2],
    ['id' => 3],
]);

$collection
   ->prioritize(function(array $item) {
      return $item['id'] === 2;
   })
   ->pluck('id')
   ->toArray(); // returns [2, 1, 3]

recursive

Convert an array and its children to collection using recursion.

collect([
  'item' => [
     'children' => []
  ]   
])->recursive();

// subsequent arrays are now collections

rotate

Rotate the items in the collection with given offset

$collection = collect([1, 2, 3, 4, 5, 6]);

$rotate = $collection->rotate(1);

$rotate->toArray();

// [2, 3, 4, 5, 6, 1]

sectionBy

Splits a collection into sections grouped by a given key. Similar to groupBy but respects the order of the items in the collection and reuses existing keys.

$collection = collect([
    ['name' => 'Lesson 1', 'module' => 'Basics'],
    ['name' => 'Lesson 2', 'module' => 'Basics'],
    ['name' => 'Lesson 3', 'module' => 'Advanced'],
    ['name' => 'Lesson 4', 'module' => 'Advanced'],
    ['name' => 'Lesson 5', 'module' => 'Basics'],
]);

$collection->sectionBy('module');

// [
//     ['Basics', [
//         ['name' => 'Lesson 1', 'module' => 'Basics'],
//         ['name' => 'Lesson 2', 'module' => 'Basics'],
//     ]],
//     ['Advanced', [
//         ['name' => 'Lesson 3', 'module' => 'Advanced'],
//         ['name' => 'Lesson 4', 'module' => 'Advanced'],
//     ]],
//     ['Basics', [
//         ['name' => 'Lesson 5', 'module' => 'Basics'],
//     ]],
// ];

Full signature: sectionBy($callback, $preserveKeys, $sectionKey, $itemsKey)

simplePaginate

Create a Paginator instance for the items in the collection.

collect($posts)->simplePaginate(5);

This paginates the contents of $posts with 5 items per page. simplePaginate accepts quite some options, head over to the Laravel docs for an in-depth guide.

simplePaginate(int $perPage = 15, string $pageName = 'page', int $page = null, int $total = null, array $options = [])

For a in-depth guide on pagination, check out the Laravel docs.

sliceBefore

Slice the values out from a collection before the given callback is true. If the optional parameter $preserveKeys as true is passed, it will preserve the original keys.

collect([20, 51, 10, 50, 66])->sliceBefore(function($item) {
    return $item > 50;
}); // return collect([[20],[51, 10, 50], [66])

tail

Extract the tail from a collection. So everything except the first element. It's a shorthand for slice(1)->values(), but nevertheless very handy. If the optional parameter $preserveKeys as true is passed, it will preserve the keys and fallback to slice(1).

collect([1, 2, 3])->tail(); // return collect([2, 3])

toPairs

Transform a collection into an array with pairs.

$collection = collect(['a' => 'b', 'c' => 'd', 'e' => 'f'])->toPairs();

$collection->toArray(); // returns ['a', 'b'], ['c', 'd'], ['e', 'f']

transpose

The goal of transpose is to rotate a multidimensional array, turning the rows into columns and the columns into rows.

collect([
    ['Jane', 'Bob', 'Mary'],
    ['jane@example.com', 'bob@example.com', 'mary@example.com'],
    ['Doctor', 'Plumber', 'Dentist'],
])->transpose()->toArray();

// [
//     ['Jane', 'jane@example.com', 'Doctor'],
//     ['Bob', 'bob@example.com', 'Plumber'],
//     ['Mary', 'mary@example.com', 'Dentist'],
// ]

try

If any of the methods between try and catch throw an exception, then the exception can be handled in catch.

collect(['a', 'b', 'c', 1, 2, 3])
    ->try()
    ->map(fn ($letter) => strtoupper($letter))
    ->each(function() {
        throw new Exception('Explosions in the sky');
    })
    ->catch(function (Exception $exception) {
        // handle exception here
    })
    ->map(function() {
        // further operations can be done, if the exception wasn't rethrow in the `catch`
    });

While the methods are named try/catch for familiarity with PHP, the collection itself behaves more like a database transaction. So when an exception is thrown, the original collection (before the try) is returned.

You may gain access to the collection within catch by adding a second parameter to your handler. You may also manipulate the collection within catch by returning a value.

$collection = collect(['a', 'b', 'c', 1, 2, 3])
    ->try()
    ->map(function ($item) {
        throw new Exception();
    })
    ->catch(function (Exception $exception, $collection) {
        return collect(['d', 'e', 'f']);
    })
    ->map(function ($item) {
        return strtoupper($item);
    });

// ['D', 'E', 'F']

validate

Returns true if the given $callback returns true for every item. If $callback is a string or an array, regard it as a validation rule.

collect(['foo', 'foo'])->validate(function ($item) {
   return $item === 'foo';
}); // returns true


collect(['sebastian@spatie.be', 'bla'])->validate('email'); // returns false
collect(['sebastian@spatie.be', 'freek@spatie.be'])->validate('email'); // returns true

weightedRandom

Returns a random item by a weight. In this example, the item with a has the most chance to get picked, and the item with c the least.

// pass the field name that should be used as a weight

$randomItem = collect([
    ['value' => 'a', 'weight' => 30],
    ['value' => 'b', 'weight' => 20],
    ['value' => 'c', 'weight' => 10],
])->weightedRandom('weight');

Alternatively, you can pass a callable to get the weight.

$randomItem = collect([
    ['value' => 'a', 'weight' => 30],
    ['value' => 'b', 'weight' => 20],
    ['value' => 'c', 'weight' => 10],
])->weightedRandom(function(array $item) {
   return $item['weight'];
});

withSize

Create a new collection with the specified amount of items.

Collection::withSize(1)->toArray(); // return [1];
Collection::withSize(5)->toArray(); // return [1,2,3,4,5];

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

$ composer test

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail security@spatie.be instead of using the issue tracker.

Credits

About Spatie

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Author: Spatie
Source Code: https://github.com/spatie/laravel-collection-macros 
License: View license

#laravel #collections #macro #php 

Laravel-collection-macros: A Set Of Useful Laravel Collection Macros
Best of Crypto

Best of Crypto

1648079400

A General Purpose OpenAPI Code Generator for Algorand

generator

This is a general purpose OpenAPI code generator. It is currently used to completely generate the HTTP code in the Java SDK, and generate some of the HTTP code in our Golang SDK.

Usage

We currently have two HTTP endpoints. One for algod and one for indexer, so in most cases, this tool would be run once with each OpenAPI spec.

Build as a self-executing jar:

~$ mvn package -DskipTests
~$ java -jar target/generator-*-jar-with-dependencies.jar -h

You'll see that there are a number of subcommands:

  • java - the original Java SDK generator.
  • responses - generate randomized test files for SDK unit tests.
  • template - a generator that uses velocity templates rather than Java code to configure the code generation.

Code layout

The command line interface uses JCommander to define the command line interface. See Main.java.

The main code involves an OpenAPI parser / event generator and several listeners for the actual generation.

object layout

Templates

The template subcommand is using Apache Velocity as the underlying template engine. Things like variables, loops, and statements are all supported. So business logic can technically be implemented in the template if it's actually necessary.

Template files

There are three phases: client, query, and model. Each phase must provide two templates, one for the file generation and one to specify the filename to be used. If all results should go to the same file. For query and model generation the template will be executed once for each query / model. If you want to put everything in one file return the same filename twice in a row and the processing will exit early.

phasefilenamepurpose
clientclient.vmClient class with functions to call each query.
clientclient_filename.vmFile to write to the client output directory.
queryquery.vmTemplate to use for generating query files.
queryquery_filename.vmFile to write to the query output directory.
modelmodel.vmTemplate to use for generating model files.
modelmodel_filename.vmFile to write to the model output directory.

Output directories

The template command will only run the templates which have an output directory is provided. So if you just want to regenerate models, only use the -m option.

  -c, --clientOutputDir
    Directory to write client file(s).
  -m, --modelsOutputDir
    Directory to write model file(s).
  -q, --queryOutputDir
    Directory to write query file(s).

Property files

The template subcommand accepts a --propertyFiles option. It can be provided multiple times, or as a comma separated list of files. Property files will be processed and bound to a velocity variable available to templates.

template variables

For details on a type you can put it directly into your template. It will be serialized along with its fields for your reference. Here is a high level description of what is available:

templatevariabletypepurpose
allstrStringHelpers.javaSome string utilities are available. See StringHelpers.java for details. There are simple things like $str.capitalize("someData") -> SomeData, and also some more complex helpers like $str.formatDoc($query.doc, "// ") which will split the document at the word boundary nearest to 80 characters without going over, and add a prefix to each new line.
allorderOrderHelpers.javaSome ordering utilities available. See OrderHelpers.java for details. An example utility function is $order.propertiesWithOrdering($props, $preferred_order), where $props is a list of properties and $preferred_order is a string list to use when ordering the properties list.
allpropFilePropertiesThe contents of all property files are available with this variable. For example if package=com.algorand.v2.algod is in the property file, the template may use ${propFile.package}.
allmodelsHashMap<StructDef, List<TypeDef>>A list of all models.
allqueriesList<QueryDef>A list of all queries.
queryqQueryDefThe current query definition.
modeldefStructDefThe current model definition if multiple files are being generated.
modelpropsList<TypeDef>A list of properties for the current model.

Example usage

In the following example, we are careful to generate the algod code first because the algod models are a strict subset of the indexer models. For that reason, we are able to reuse some overlapping models from indexer in algod.

~$ java -jar generator*jar template
        -s algod.oas2.json
        -t go_templates
        -c algodClient
        -m allModels
        -q algodQueries
        -p common_config.properties,algod_config.properties
~$ java -jar generator*jar template
        -s indexer.oas2.json
        -t go_templates
        -c indexerClient
        -m allModels
        -q indexerQueries
        -p common_config.properties,indexer_config.properties

Test Template

There is a test template that gives you some basic usage in the test_templates directory.

You can generate the test code in the output directory with the following commands:

~$ mkdir output
~$ java -jar target/generator-*-jar-with-dependencies.jar \
    template \
    -s /path/to/a/spec/file/indexer.oas2.json \
    -t test_templates/ \
    -m output \
    -q output \
    -c output \
    -p test_templates/my.properties

Golang Template

The Golang templates are in the go_templates directory.

The Golang HTTP API is only partially generated. The hand written parts were not totally consistent with the spec and that makes it difficult to regenerate them. Regardless, an attempt has been made. In the templates there are some macros which map "generated" values to the hand written ones. For example the query types have this mapping:

#macro ( queryType )
#if ( ${str.capitalize($q.name)} == "SearchForAccounts" )
SearchAccounts## The hand written client doesn't quite match the spec...
#elseif ( ${str.capitalize($q.name)} == "GetStatus" )
Status##
#elseif ( ${str.capitalize($q.name)} == "GetPendingTransactionsByAddress" )
PendingTransactionInformationByAddress##
#elseif ( ${str.capitalize($q.name)} == "GetPendingTransactions" )
PendingTransactions##
#else
${str.capitalize($q.name)}##
#end
#end

Other mappings are more specific to the language, such as the OpenAPI type to SDK type:

#macro ( toQueryType $param )##
#if ( $param.algorandFormat == "RFC3339 String" )
string##
#elseif ( $param.type == "integer" )
uint64##
#elseif ( $param.type == "string" )
string##
#elseif ( $param.type == "boolean" )
bool##
#elseif( $param.type == "binary" )
string##
#else
UNHANDLED TYPE
- ref: $!param.refType
- type: $!param.type
- array type: $!param.arrayType
- algorand format: $!param.algorandFormat
- format: $!param.format
##$unknown.type ## force a template failure because $unknown.type does not exist.
#end
#end

Because of this, we are phasing in code generation gradually by skipping some types. The skipped types are specified in the property files:

common_config.properties

model_skip=AccountParticipation,AssetParams,RawBlockJson,etc,...

algod_config.properties

query_skip=Block,BlockRaw,SendRawTransaction,SuggestedParams,etc,...

indexer_config.properties

query_skip=LookupAssetByID,LookupAccountTransactions,SearchForAssets,LookupAssetBalances,LookupAssetTransactions,LookupBlock,LookupTransactions,SearchForTransactions

Java Template

The Java templates are in the java_templates directory.

These are not used yet, they are the initial experiments for the template engine. Since the Java SDK has used code generation from the beginning, we should be able to fully migrate to the template engine eventually.

Automation

Preparing an external repository for automatic code generation

In general, the automation pipeline will build and run whatever Dockerfile is found in a repository's templates directory. For instructions on how to configure the templates directory, look at the repository template directory example.

If you are trying to verify that automatic code generation works as intended, we recommend creating a testing branch from that repository and using the SKIP_PR=true environment variable to avoid creating pull requests. If all goes according to plan, generated files should be available in the container's /repo directory.

Setting up the automatic generator

The automatic generator scripts depend on certain prerequisites that are listed in automation/REQUIREMENTS.md. Once those conditions have been satisfied, automatically generating code for external repositories should be as easy as building and running a particular SDK's templates/Dockerfile file.


Download Details:
Author: algorand
Source Code: https://github.com/algorand/generator
License:

#algorand  #blockchain  #cryptocurrency #java #golang #openapi 

A General Purpose OpenAPI Code Generator for Algorand
Cyril  Parisian

Cyril Parisian

1642874400

How to insert Custom C++ Code Into GameMaker Studio 2 Builds YYC

YYC Boost

Inject custom C++ code into GameMaker Studio 2 YYC builds!

WARNING: This tool is currently in an early stage of development and it is not guaranteed to work in all projects/cases! Use at your own risk! Currently only the Windows YYC target is supported!

Table of Contents

Features

Multithreading

Run functions in a separate thread!

yyc_run_in_thread(function () {
    while (true)
    {
        show_debug_message("This does not block the main thread!");
    }
});

Task system

Utilize multithreading for parallel tasks! Includes fallback for VM.

var _sleepTask = function (_arg) {
    var _ms = _arg[0];
    var _message = _arg[1];
    var _t = current_time;
    while (current_time - _t < _ms) {}
    show_debug_message(_message);
};

// Create standalone tasks:
new YYC_Task(_sleepTask, [1000, "Standalone task done!"]).Run();

// Or groups of tasks:
new YYC_GroupTask([
    new YYC_Task(_sleepTask, [1000, "Task 1 done!"]),
    new YYC_Task(_sleepTask, [2000, "Task 2 done!"]),
    new YYC_Task(_sleepTask, [3000, "Task 3 done!"]),
], _sleepTask, [1000, "Group 1 done!"]).Run();

C++ types of local variables

Define C++ type of a var to save memory and increase performance!

#macro COUNT 10000
var _t;

_t = get_timer();
for (var i = 0; i < COUNT; ++i) {}
show_debug_message(get_timer() - _t);

// This loop runs faster compared to when a regular var is used
_t = get_timer();
for (var j/*:int*/= 0; j < COUNT; ++j) {}
show_debug_message(get_timer() - _t);

C++ code injection

Replace function with a custom C++ code!

/// @desc Returns 1 when YYC Boost is used, otherwise 0.
function is_cpp()
{
    /*cpp
    _result = 1;
    return _result;
    */
    return 0;
}

Documentation

Online documentation for the latest release of YYC Boost is available here.

Building from source code

Requires Python 3!

git clone https://github.com/kraifpatrik/YYCBoost
cd .\YYCBoost\YYCBoost_CLI\
python.exe -m venv env
.\env\Scripts\activate
pip.exe install -r requirements.txt
python.exe setup.py

This will create a directory YYCBoost\YYCBoost_CLI\dist with yycboost.exe.

Links


Author: kraifpatrik
Source Code: https://github.com/kraifpatrik/YYC-Boost
License: MIT License

#cpluplus 

How to insert Custom C++ Code Into GameMaker Studio 2 Builds YYC
Oleta  Becker

Oleta Becker

1604289180

Saving Data to Google Sheets From BigQuery

It’s been a while since I’ve started working on datasets with BigQuery. Most of the time, I need to generate reports for several teams that work with/love spreadsheets. There are multiple ways to extract and present data (Connecting to Data Studio, Google Sheets via OWOX, etc.), but today I’m just going to show you one way.

Extracting and Saving to Google Sheets

Have your query prepared, and for those of you starting out, here’s the general syntax.

SELECT * FROM `GCP_Project_Name.Dataset.Table`
WHERE [CONDITIONS]

There are 2 options you can choose from when extracting:

Option 1

If your query is fairly simple and completes relatively quickly, I’d suggest to run the query from Google sheets directly using the native data connector (You may need to have a GSuite subscription for this feature).

Click on “Connect to BigQuery”, select the project, paste the query, then click “Insert results”.

#bigquery #google-sheets #data #macro #data-science

Saving Data to Google Sheets From BigQuery

Julia’s Most Awesome Features

Within the bounds of programming languages are programming concepts and paradigms. Many languages take advantage of both their paradigm, as well as interesting generic programming concepts to create features to differentiate themselves from other languages. However, these features are often limited in scope, and sometimes aren’t used frequently enough to even justify being around.

The Julia programming language is an interesting case because unlike most languages, Julia has some killer defining features that make it capable of various different things that you might not expect to go together. Though there is certainly an enormous list of fantastic features that the Julia language utilizes, these are five of those features that I find the most useful and engaging.


№1: Macros

Image for post

Although macros are certainly not a new concept to programming, their implementation in Julia is rather unique and in my subjective opinion rather well done. Macros are “ shortcuts” that can be used to quickly and effectively access functions, and are incredibly useful when working with functional applications of the Julia language. In Julia, you can define a macro by simply using “ macro.”

macro add(num1,num2)
   num1 + num2 
end

And we can use the macro by adding the @ symbol before the name of the macro. The parameters can be added with white-space, no parenthesis or commas necessary!

#computer-science #programming #macro #julia #gpu #data science

Julia’s Most Awesome Features