1680174480
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
.
Author: Matklad
Source Code: https://github.com/matklad/once_cell
License: Apache-2.0, MIT licenses found
1670675543
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.
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:
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.
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?
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.
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.
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/
1668170460
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 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.)
- 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 whetherif
conditions are satisfied. This means that the loop should not include statements with side effects (like
Author: StephenVavasis
Source Code: https://github.com/StephenVavasis/Unroll.jl
License: MIT license
1667576880
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.
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:
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:
x = 5
) is encountered, then add the target of the assignment (x
in this case) to the disqualified symbols.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).
Author: rdeits
Source Code: https://github.com/rdeits/CommonSubexpressions.jl
License: View license
1667439840
Easy memoization for Julia.
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
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.
Author: JuliaCollections
Source Code: https://github.com/JuliaCollections/Memoize.jl
License: View license
1665689040
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
Author: Simonbyrne
Source Code: https://github.com/simonbyrne/InplaceOps.jl
License: View license
1664318160
Julia package for deconstructing dispatch on NamedTuple
s.
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
Author: Tpapp
Source Code: https://github.com/tpapp/EponymTuples.jl
License: View license
1664298600
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!")
@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
Author: Mauro3
Source Code: https://github.com/mauro3/UnPack.jl
License: MIT license
1658290740
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.
You can pull in the package via composer:
composer require spatie/laravel-collection-macros
The package will automatically register itself.
after
at
before
catch
chunkBy
collectBy
eachCons
extract
filterMap
firstOrFail
firstOrPush
fromPairs
glob
groupByModel
head
if
ifAny
ifEmpty
insertAfter
insertAfterKey
insertAt
insertBefore
insertBeforeKey
none
paginate
parallelMap
path
pluckMany
pluckToArray
prioritize
recursive
rotate
sectionBy
simplePaginate
sliceBefore
tail
try
toPairs
transpose
validate
weightedRandom
withSize
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 arraynull
instead of omitting itextract
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];
Please see CHANGELOG for more information what has changed recently.
$ composer test
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.
Please see CONTRIBUTING for details.
If you've found a bug regarding security please mail security@spatie.be instead of using the issue tracker.
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
1648079400
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.
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.
~$ mvn package -DskipTests
~$ java -jar target/generator-*-jar-with-dependencies.jar -h
You'll see that there are a number of subcommands:
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.
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.
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.
phase | filename | purpose |
---|---|---|
client | client.vm | Client class with functions to call each query. |
client | client_filename.vm | File to write to the client output directory. |
query | query.vm | Template to use for generating query files. |
query | query_filename.vm | File to write to the query output directory. |
model | model.vm | Template to use for generating model files. |
model | model_filename.vm | File to write to the model output directory. |
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).
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.
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:
template | variable | type | purpose |
---|---|---|---|
all | str | StringHelpers.java | Some 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. |
all | order | OrderHelpers.java | Some 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. |
all | propFile | Properties | The 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} . |
all | models | HashMap<StructDef, List<TypeDef>> | A list of all models. |
all | queries | List<QueryDef> | A list of all queries. |
query | q | QueryDef | The current query definition. |
model | def | StructDef | The current model definition if multiple files are being generated. |
model | props | List<TypeDef> | A list of properties for the current model. |
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
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
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
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.
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.
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
1642874400
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
Run functions in a separate thread!
yyc_run_in_thread(function () {
while (true)
{
show_debug_message("This does not block the main thread!");
}
});
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();
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);
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
1604289180
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
1598704380
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.
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