Simple Modifications ->
For your device (select it) ->
Add item -> application (Keys in pc keybords) ->
right_command (Modifier keys)
There you go - it started functioning well.
Mechanical keyboard on Mac OS. When the right command key does not work properly.
Recetly I decided to switch from an Apple magic keyboard to the on of the mechanical keyboard I bought the other day on the Aliexpress. It's the GK85 one with red switches.
Despite the fact this keyboard wasn't expensive the typing felt pretty good. Although the keyboard was compatible with the Mac OS, I faced that the right command key did not work as expected. Then the Karabiner Elements app came to my aid. In Karabiner-EventViwer I was able to determine the correct key-code that was associated with this key. In my case it was {"key_code": "application"}. So, there was just one thing left to do - map this key_code to the key_code I needed - right_command:
Golang. Working with go module dependencies
In order to initialize go modules in our project just run the next command
This file also contains the following elements:
require includes all dependency modules and the associated version that we are going to use in our project.
replace points to the local version of the dependency in Go, not git-web. It will create a local copy of the provider with available versions, so there is no need to install every time we want to refer to the provider.
//indirect implies that we do not use these dependencies inside our project, but there is some module that imports them.
go.sum maintains a checksum, so when we run the project again, it won't install all the packages again. It uses the cache, which is stored in the $GOPATH/pkg/mod directory (module cache directory).
It is possible to create a separate catalog of vendors with available versions. This copies all third-party dependencies to the vendor folder at the root of your project. This adds all the transitive dependencies needed to run the vendor’s package. When vendoring is enabled, the go command will download packages from the vendor directory instead of downloading modules from their sources into the module cache and using the already downloaded packages.
There is a command to remove installed packages. This command is used to clear the mod cache, which is stored in $GOPATH/pkg/mod. The -modcache flag removes the entire module load cache, including unpacked dependency version source code.
To view a list of available package versions
To view a list of available versions of all packages that are used in your project
The list of available versions will only be displayed if the package has a release version. In this case, if a package is used that does not have a release version, then go.mod will display an entry in the following format instead of the version - v0.0.0-<timestamp>-<commit-hash> In fact, the availability of a release version can also be found through git commands:
Upgrading dependency to the latest version
Upgrading dependency and all its dependencies to the latest version
Viewing available dependency upgrades. It will show you available minor and patch upgrades for all direct and indirect dependencies
Upgrading all dependencies at once. To upgrade all dependencies at once for a given module, just run the following from the root of your module. This upgrades to the latest or minor patch release
Or we can upgrade test dependencies
To also upgrade to a specific version using Go modules
or specifying a commit hash
We can update the package to the latest available version and thus
Thus, given the required version, we can perform downgrading and upgrading. After all such updates and changes in the project code, it is recommended to run the command
This will then link the current imports in the project and packages listed in go.mod go mod tidy ensures that the go.mod file matches the source code of the module. It adds any missing module requirements needed to build the current module's packages and dependencies, if there are any unused dependencies, go mod tidy will remove them from go.mod accordingly. It also adds any missing entries to go.sum and removes unnecessary entries.
go mod init github.com/<user>/<project>
As a result, go.mod and go.sum will be created.
go.mod file describes all the dependencies in the project, as well as the current version of the language and initialized module name.
This file also contains the following elements:
require includes all dependency modules and the associated version that we are going to use in our project.
replace points to the local version of the dependency in Go, not git-web. It will create a local copy of the provider with available versions, so there is no need to install every time we want to refer to the provider.
//indirect implies that we do not use these dependencies inside our project, but there is some module that imports them.
go.sum maintains a checksum, so when we run the project again, it won't install all the packages again. It uses the cache, which is stored in the $GOPATH/pkg/mod directory (module cache directory).
It is possible to create a separate catalog of vendors with available versions. This copies all third-party dependencies to the vendor folder at the root of your project. This adds all the transitive dependencies needed to run the vendor’s package. When vendoring is enabled, the go command will download packages from the vendor directory instead of downloading modules from their sources into the module cache and using the already downloaded packages.
go mod vendor
There is a command to remove installed packages. This command is used to clear the mod cache, which is stored in $GOPATH/pkg/mod. The -modcache flag removes the entire module load cache, including unpacked dependency version source code.
go clean -modcache
To view a list of available package versions
go list -m -versions github.com/pkg/math
To view a list of available versions of all packages that are used in your project
go list -m all
The list of available versions will only be displayed if the package has a release version. In this case, if a package is used that does not have a release version, then go.mod will display an entry in the following format instead of the version - v0.0.0-<timestamp>-<commit-hash> In fact, the availability of a release version can also be found through git commands:
git ls-remote —tags git://github.com/.git | less
git ls-remote —heads git://github.com/.git | less
Upgrading dependency to the latest version
go get example.com/pkg
Upgrading dependency and all its dependencies to the latest version
go get -u example.com/pkg
Viewing available dependency upgrades. It will show you available minor and patch upgrades for all direct and indirect dependencies
go list -u -m all
Upgrading all dependencies at once. To upgrade all dependencies at once for a given module, just run the following from the root of your module. This upgrades to the latest or minor patch release
go get -u ./...
Or we can upgrade test dependencies
go get -t -u ./...
To also upgrade to a specific version using Go modules
go get foo@v1.2.3
go get github.com/pkg/math@v0.3.0
or specifying a commit hash
go get foo@f5801deq7
We can update the package to the latest available version and thus
go get github.com/pkg/math@latest
Thus, given the required version, we can perform downgrading and upgrading. After all such updates and changes in the project code, it is recommended to run the command
go mod tidy
This will then link the current imports in the project and packages listed in go.mod go mod tidy ensures that the go.mod file matches the source code of the module. It adds any missing module requirements needed to build the current module's packages and dependencies, if there are any unused dependencies, go mod tidy will remove them from go.mod accordingly. It also adds any missing entries to go.sum and removes unnecessary entries.
Golang. Encapsulation via interfaces
How we can use all power of encapsulation in golang?
To achieve that we can use so-called interfaces. Below you can see one example of that approach. Our Notifier interface is public and the notifier struct is private. It means that all external clients will be able to use notifiers package publicly only via public interface while other things are hidden. So it’s the power of using encapsulation.
There is only one thing we can do to fix it. This is to make the return struct public.
To achieve that we can use so-called interfaces. Below you can see one example of that approach. Our Notifier interface is public and the notifier struct is private. It means that all external clients will be able to use notifiers package publicly only via public interface while other things are hidden. So it’s the power of using encapsulation.
package notifiers
import "fmt"
type Notifier interface {
Send()
}
type notifier struct {
client string
}
func NewNotifier(client string) Notifier {
return ¬ifier{client: client}
}
func (n *notifier) Send() {
fmt.Printf("Notifier sent notification via client: %v\n", n.client)
}
package main
import "notifiers"
func main() {
notifiers.NewNotifier("html client").Send()
}
But what if we need to get access to the state of returning struct instance from the package instead of being able to work only with the public interface?
In that case, we can change the return type in the signature of the public constructor NewNotifier.
func NewNotifier(client string) *notifier {
return ¬ifier{client: client}
}
And it will be workable. But if you try to run golint then you will get the next error message:
exported func NewNotifier returns unexported type *notifier, which can be annoying to use (golint)
There is only one thing we can do to fix it. This is to make the return struct public.
package notifiers
import "fmt"
type Notifier struct {
client string
}
func NewNotifier(client string) *Notifier {
return &Notifier{client: client}
}
func (n *Notifier) Send() {
fmt.Printf("Notifier sent notification via client: %v\n", n.client)
}
As you can see, the Notifier interface had to be removed.
Thus, we threw more details out. In my opinion, it’s a less abstract approach.
Despite this, we can still use encapsulation both at the package and at the level of public structure (by using private fields).
Ruby. Working with PostGIS extension
Postgres is well known as a modern and powerful database.
One of the possibilities is support for working with geospatial data.
Initially, this requires the installation of the PostGIS extension.
Next, in your rails application, you need to use gems such as:
- gem 'activerecord-postgis-adapter'
- gem 'rgeo'
- gem 'geocoder'
Below is an example of working with a truck model, in which one of the fields (let's call it waypoints) has a special data type - geometry(linestring).
# app/lib/geo.rb
class Geo
SRID = 4326
METHODS = %i[point line_string]
class << self
delegate *METHODS, prefix: 'cartesian', to: :cartesian_factory
delegate *METHODS, prefix: 'spherical', to: :spherical_factory
def cartesian_factory
@cartesian_factory ||= RGeo::Cartesian.factory
end
def spherical_factory
@spherical_factory ||= RGeo::Geographic.spherical_factory(srid: SRID)
end
def pairs_to_points(pairs)
pairs.map { |pair| point(pair[0], pair[1]) }
end
def pairs_to_line_string(pairs)
points = pairs_to_points(pairs)
cartesian_line_string(points)
end
end
end
# app/models/concerns/geo_workable.rb
module GeoWorkable
extend ActiveSupport::Concern
METHODS = %i[pairs_to_points pairs_to_line_string].freeze
included do
delegate *METHODS, to: Geo
end
class_methods do
delegate *METHODS, to: Geo
end
end
# app/models/track.rb
class Track < ActiveRecord::Base
include GeoWorkable
def coordinates
self.waypoints.coordinates
end
def update_waypoints(coordinates)
self.waypoints = pairs_to_line_string(coordinates)
self.save
end
end
track = Track.find(...)
coordinates = track.coordinates # [[longitude, latitude], [longitude, latitude], ...]
# do some transformations on that coordinates
track.update_waypoints(coordinates)
Golang. A simple concept of a constructor
In Go it does not exist the concept of a constructor like in other languages. A
struct is a very flexible construct that can be defined in many ways. When
working with structs it is very important to take into consideration fields zero
values and how these values may impact the code. In many cases, it is a good
practice to define constructors, especially when certain values are not valid.
package main
type Box struct {
Height int
Width int
}
// It's a kind of constructor
func NewBox(height int, width int) (*Box, error) {
if height <= 0 || width <= 0 {
return nil, errors.New("params must be greater than zero")
}
return &Box{height, width}, nil
}
func main() {
b, err := NewBox(1, 2)
if err != nil {
...
}
}
JavaEE/WildFly/vscode. Debugging a web application in the vscode in conjunction with the WildFly server
As an experiment, I tried to debug a simple web application running on the WildFly server in vscode.
Of course, vscode does not have the same completeness as IntelliJ IDEA in terms of features,
but it can be considered as a kind of alternative.
So, in order to debug your application, start the WildFly server in debug mode,
specifying the port to which vscode will connect (in my case, port 8787 is specified):
standalone.sh --debug 8787
After that add the configuration:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Debug (Attach)",
"projectName": "your_project_name",
"request": "attach",
"hostName": "your_host_name",
"port": "debugging_port"
}
]
}
In my case the configuration looks like this:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Debug (Attach)",
"projectName": "webapp",
"request": "attach",
"hostName": "localhost",
"port": 8787
}
]
}
Next, start debugging by pressing F5
Now everything is ready, so you can set breakpoints and debug your application.
Happy debugging 🖖
Ruby. Iterating through a collection within specified a window
Rust has a method - windows (or equivalent - chunks)
fn main() {
let ints = [0, 1, 2, 3, 4, 5, 6, 7, 8];
let slice = &ints;
for el in slice.windows(3) {
println!("window {:?}", el)
}
}
that allows you to iterate through a slice and read elements within specified a window.
Below is the implementation of similar functionality in Ruby:
module Enumerable
def windows(n)
raise ArgumentError.new("Expected a value greater than 0") if n <= 0
return to_enum(:windows, n) unless block_given?
return nil if self.size == 0
(0..(self.size/n)).each do |i|
l = i * n
yield self[l...(l + n)]
end
end
alias_method :chunks, :windows
end
irb(main):014:0> [0, 1, 2, 3, 4, 5, 6, 7, 8].windows(3).each { |el| puts el.join(',') }
0,1,2
3,4,5
6,7,8
irb(main):015:0> [0, 1, 2, 3, 4, 5, 6, 7, 8].windows(0).each { |el| puts el.join(',') }
(irb):3:in `windows': Expected a value greater than 0 (ArgumentError)
irb(main):016:0> windows = [0, 1, 2, 3, 4, 5, 6, 7, 8].windows(5)
=> #
irb(main):017:0> windows.each { |el| puts el.join(',') }
0,1,2,3,4
5,6,7,8
Why algorithms (in particular, I/O algorithms) are important
Suppose we have a two-dimensional array, which is a map with given heights at different points. Let's calculate the average elevation.
To do this, you can go through either each row:
sum = 0
for i = 0 to m - 1 do
for j = 0 to m - 1 do
sum = sum + A[i, j]
avg = sum / m^2
or each column:
sum = 0
for j = 0 to m - 1 do
for i = 0 to m - 1 do
sum = sum + A[i, j]
avg = sum / m^2
Then summarize all heights and divide by the number of points on the map.
Do you think there is any difference between these methods?
It would seem not, but in fact, there is. The first method (traversing all rows) turns out to be more productive than the second method (traversing the columns).
The whole thing is related to the organization of the array in memory and access to each cell.
I tried to compare on Java. That's what I did.
// Computing the average elevation
class Avg {
public static void main(String[] argv) {
int n = 1000; // 1000 * 1000 = 10^6
int[][] matrix = new int[n][n];
fillMatrix(matrix, n, 1);
long start = System.nanoTime();
int avg = avgRowByRow(matrix);
System.out.println(String.format(
"avg (Row By Row) = %s,
it takes %s nano-seconds",
avg,
System.nanoTime() - start
));
start = System.nanoTime();
avg = avgColumnByColumn(matrix);
System.out.println(String.format(
"avg (Column By Column) = %s
it takes %s nano-seconds",
avg,
System.nanoTime() - start
));
}
private static void fillMatrix(int[][] matrix, int n, int default_value) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = default_value;
}
}
}
private static int avgRowByRow(int[][] matrix) {
int sum = 0, m = matrix.length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
sum = sum + matrix[i][j];
}
}
return sum / m / m; // sum / (m * m)
}
private static int avgColumnByColumn(int[][] matrix) {
int sum = 0, m = matrix.length;
for (int j = 0; j < m; j++) {
for (int i = 0; i < m; i++) {
sum = sum + matrix[i][j];
}
}
return sum / m / m; // sum / (m * m)
}
}
Then I tried to run it a couple of times and got the following result.
The result can be said to be obvious:
avg (Row By Row) = 1, it takes 3822568 nano-seconds avg (Column By Column) = 1, it takes 5646746 nano-seconds avg (Row By Row) = 1, it takes 3902352 nano-seconds avg (Column By Column) = 1, it takes 5467638 nano-seconds avg (Row By Row) = 1, it takes 3939734 nano-seconds avg (Column By Column) = 1, it takes 5077092 nano-seconds avg (Row By Row) = 1, it takes 3736544 nano-seconds avg (Column By Column) = 1, it takes 4950847 nano-seconds avg (Row By Row) = 1, it takes 3900019 nano-seconds avg (Column By Column) = 1, it takes 5009578 nano-seconds avg (Row By Row) = 1, it takes 3954720 nano-seconds avg (Column By Column) = 1, it takes 5109380 nano-seconds avg (Row By Row) = 1, it takes 3824056 nano-seconds avg (Column By Column) = 1, it takes 5276105 nano-seconds
API Documentation. Multiple examples in Swagger
When describing the API documentation, sometimes there is a need to add several examples of responses.
This is necessary for the possibility of a more complete description of the API documentation,
since this API documentation is a kind of contract between the backend and the frontend.
If you still use Swagger v.2.0 then you face the limitation - adding multiple examples is not supported.
To get around this limitation, you need to go to the OpenAPI v. 3.0.0 specification.
Then you will be able to add examples as follows.
- One example:
The differences between Swagger v.2.0 and the OpenAPI v. 3.0.0 specification are generally not so big:
- One example:
responses:
"200":
description: user creation successful
content:
application/json:
example:
token: fEt4IouUyRrqlx80treEWwq8
- A few examples:
responses:
"422":
description: user creation failed
content:
application/json:
schema:
properties:
response:
$ref: "#/components/schemas/ErrorResponse"
examples:
"Missing parameters":
value:
error: 'error-1'
message: 'error-message-1'
"Validation failed":
value:
error: 'error-2'
message: 'error-message-2'
The differences between Swagger v.2.0 and the OpenAPI v. 3.0.0 specification are generally not so big:
Swagger v.2.0 | OpenAPI v.3.0.0
----------------------|-------------------
info | info
----------------------|-------------------
host |
basePath | servers
schemes |
----------------------|-------------------
security | security
----------------------|-------------------
paths | paths
----------------------|-------------------
externalDocs | externalDocs
----------------------|-------------------
tags | tags
----------------------|-------------------
|
securityDefinitions |
| components:
----------------------| parameters
produces | responses
----------------------| examples
consumes | requestBodies
----------------------| headers
definitions | links
parameters | callbacks
responses | securitySchemes
|
So the transition itself should not be difficult.
Rspec. When hashes are used inside arrays
I'm always amazed at the flexibility of unit testing when working with Ruby projects.
Below are examples of such flexibility in which you can check the contents of hashes nested in an array.
context 'when hashes in array' do
let(:hash_set) do
[
{ attr1: 1, attr2: 2 },
{ attr1: 3, attr2: 4 }
]
end
let(:attribute_keys) { %i[attr1 attr2] }
it 'contains a set of attribute keys' do
expect(hash_set).to all(include(*attribute_keys))
end
end
context 'when hashes in nested array' do
let(:hash_set) do
[
{ attr1: 1, attr2: [{ attr3: 3, attr4: 4 }] },
{ attr1: 5, attr2: [{ attr3: 6, attr4: 7 }] }
]
end
let(:first_attribute_keys) { %i[attr1 attr2] }
let(:second_attribute_keys) { %i[attr3 attr4] }
it 'contains a set of first attribute keys' do
expect(hash_set).to all(include(*first_attribute_keys))
end
it 'contains a set of second attribute keys' do
expect(hash_set).to all(
include(attr2: all(include(*second_attribute_keys)))
)
end
end
# Some class for testing
class Tester
def exec(options)
# some work
end
end
context 'when hashes are passed as parameters' do
subject(:tester) { Tester.new }
let(:options) do
{
attr1: 1,
attr2: { attr4: 2 },
attr3: [
{ attr5: 3 },
{ attr6: 4 }
]
}
end
it 'contains a set of attribute keys with values' do
expect(tester).to receive(:exec).with(
hash_including(
attr1: 1,
attr2: hash_including(attr4: 2),
attr3: [hash_including(attr5: 3), hash_including(attr6: 4)]
)
)
tester.exec(options)
end
it 'contains a set of attribute keys' do
expect(tester).to receive(:exec).with(
hash_including(
:attr1,
attr2: hash_including(:attr4),
attr3: array_including(hash_including(:attr5), hash_including(:attr6))
)
)
tester.exec(options)
end
end
Ruby. Messages from RuboCop about using predefined variables
Ruby has a lot of predefined variables.
The one of them is $/. It is used as a universal substitution of newline symbol:
> numbers = ['one', 'two', 'three']
=> ["one", "two", "three"]
> numbers.join($/)
=> "one\ntwo\nthree"
> puts numbers.join($/)
one
two
three
=> nil
RuboCop is a Ruby code style checker (linter) and formatter based on the community-driven Ruby Style Guide.
If you use it in your project, then it is possible that you will face with the next problem when using $/:
Prefer `$INPUT_RECORD_SEPARATOR` or `$RS` from the stdlib 'English' module (don't forget to require it) over `$/`.(convention:Style/SpecialGlobalVars)To fix it you can do like this:
# readable global var aliases
require 'English'
...
def log_error(error)
backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
backtrace_cleaner.add_filter { |line| line.gsub(Rails.root.to_s, '') }
backtrace_cleaner.add_silencer { |line| line =~ /puma|rubygems/ }
Rails.logger.error(
[
"#{error.class}: #{error.message}",
*backtrace_cleaner.clean(error.backtrace)
].join($RS)
)
end
...
As you can see I have used the $RS. Instead, you can use $INPUT_RECORD_SEPARATOR.
Apache Bench
The Apache software foundation offers a lot of cool tools. The one of them is Apache Bench.
It gives you ability to test and get benchmarks of handling http requests by your web service.
I currently use Ubuntu so to play around I ran next command:
sudo apt-get install apache2-utils
And fed my service to it:
ab -n 100 -c 10 http://127.0.0.1/greet
As a result, you'll get next output:
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient).....done
Server Software: nginx/1.17.6
Server Hostname: 127.0.0.1
Server Port: 80
Document Path: /greet
Document Length: 10 bytes
Concurrency Level: 10
Time taken for tests: 0.004 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 15300 bytes
HTML transferred: 1000 bytes
Requests per second: 27956.39 [#/sec] (mean)
Time per request: 0.358 [ms] (mean)
Time per request: 0.036 [ms] (mean, across all concurrent requests)
Transfer rate: 4177.08 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 0 0 0.0 0 0
Waiting: 0 0 0.0 0 0
Total: 0 0 0.0 0 0
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 0
95% 0
98% 0
99% 0
100% 0 (longest request)
Ruby/Haskell. Left and right folds
Haskell has ample opportunities to work with lists, in particular - left and right fold. For this in the Prelude module there are functions such as foldr - for the right fold and foldl - for the left fold:
Denote the anonymous function (\ x (y1, y2) -> (y2, x: y1)) by f
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f ini [] = ini
foldr f ini (x:xs) = f x (foldr f ini xs)
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f ini [] = ini
foldl f ini (x:xs) = foldl f (f ini x) xs
For an example of their use let's implement the function evenOnly, which throws out elements from the list that stand in odd places, leaving only even ones.
One of the implementations is as follows:
evenOnly :: [a] -> [a]
evenOnly = fst . foldr (\x (y1, y2) -> (y2, x:y1)) ([],[])
To do this, we used the right fold. Consider how Haskell will step by step perform the reductions with the fold of the list [1, 2, 3, 4].
Denote the anonymous function (\ x (y1, y2) -> (y2, x: y1)) by f
{- Right fold of list (steps of reductions):
foldr f ([],[]) 1:2:3:4:[]
~> f 1 (foldr f ([],[]) 2:3:4:[])
~> f 1 (f 2 (foldr f ([],[]) 3:4:[]))
~> f 1 (f 2 (f 3 (foldr f ([],[]) 4:[])))
~> f 1 (f 2 (f 3 (f 4 (foldr f ([],[]) []))))
~> f 1 (f 2 (f 3 (f 4 ([],[]))))
~> f 1 (f 2 (f 3 ([],4:[])))
~> f 1 (f 2 (4:[], 3:[]))
~> f 1 (3:[], 2:4:[])
~> (2:4:[], 1:3:[])
([2,4], [1,3])
-}
Let's change the right fold to the left in this implementation:
evenOnly :: [a] -> [a]
evenOnly = fst . foldl (\(y1, y2) x -> (y2, x:y1)) ([],[])
And also let's look how reductions will be executed step by step.
{- Left fold of list (steps of reductions):
foldl f ([],[]) 1:2:3:4:[]
~> foldl f (f ([],[]) 1) (2:3:4:[])
~> foldl f (f (f ([],[]) 1) 2) (3:4:[])
~> foldl f (f (f (f ([],[]) 1) 2) 3) (4:[])
~> foldl f (f (f (f (f ([],[]) 1) 2) 3) 4) []
~> f (f (f (f ([],[]) 1) 2) 3) 4
~> f (f (f ([],1:[]) 2) 3) 4
~> f (f (1:[],2:[]) 3) 4
~> f (2:[], 3:1:[]) 4
~> (3:1:[], 4:2:[])
([3,1], [4,2])
-}
From these examples we can see how the right and left folds differ. Also note that the implementation of evenOnly through left fold certainly behaves incorrectly, because the order of the "even" values becomes incorrect. Also pay attention to the difference of signatures of anonymous functions passed to the functions foldr and foldl.
Now we will try to implement similar functionality on Ruby. First, let's implement the functions foldr and foldl:
def foldr(f, ini, list)
return ini if list.length == 0
*xs, x = list
foldr(f, f.call(x, ini), xs)
end
def foldl(f, ini, list)
return ini if list.length == 0
x, *xs = list
foldl(f, f.call(ini, x), xs)
end
Based on the right fold:
evenOnly = ->(list) { foldr(->(x, ini) { xs, ys = ini; [ys, [x, *xs]] }, [[], []], list).first }
Based on the left fold:
evenOnly = ->(list) { foldl(->(ini, x) { xs, ys = ini; [ys, [x, *xs]] }, [[], []], list).first }
Since the left fold is incorrect (given only for demonstration), we take the right fold as the basis and run our implementation for the test a couple of times:
evenOnly.call([]) # []
evenOnly.call([1]) # []
evenOnly.call([1, 2, 3, 4]) # [2, 4]
evenOnly.call([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # [2, 4, 6, 8, 10]
Ruby/Haskell. Hoare's partition sort or quick sort. Imperative or functional approach?
Some of these days I had fun with Haskell. I tried to write Hoare's sort in Haskell.
For my implementation I used list's filtering by the element that was in the middle of the list:
This is a variant of imperative implementation:
qsort :: Ord a => [a] -> [a]
qsort [] = []
qsort xs = partitions (xs !! (div ((length xs) - 1) 2)) xs where
partitions x' xs' =
qsort (filter (< x') xs') ++ (filter (== x') xs') ++ qsort (filter (> x') xs')
What is the most interesting that using of this kind of filtering allows to write a more intuitive algorithm than a variant with an imperative implementation.
For comparison, below we can see implementations in Ruby.
This is a variant of imperative implementation:
def hoaresort(array, first, last)
i, j = first, last
x = array[(i + j) / 2]
begin
i += 1 while array[i] < x
j -= 1 while array[j] > x
if i <= j
array[i], array[j] = array[j], array[i] if i < j
i += 1
j -= 1
end
end while (i <= j)
hoaresort(array, i, last) if i < last
hoaresort(array, first, j) if first < j
# Uncomment next line if you want to return sorted array as result
# array
end
And next is a variant of functional implementation:
def hoaresort(array)
return [] if array.length == 0
x = array[(0 + (array.length - 1)) / 2]
hoaresort(array.filter { |v| v < x }) +
array.filter { |v| v == x } +
hoaresort(array.filter { |v| v > x })
end
In my opinion the comparison obviously shows us that the functional approach is more clear and understandable.
curl. Basic authentication
Specify the user name and password to use for server authentication:
curl --user <name>:<password> http://www.test.com
If you simply specify the user name, curl will prompt for a password:
curl --user <name> http://www.test.com
Also you can encrypt name and password before sending your curl request:
curl -H "Authorization: Basic <your_token>" http://www.test.com
where <your_token> is being generated like that:
-ne "<name>:<password>" | base64 --wrap 0
Git. Often used command set
Shows git tree of all commits
Moving around in Git: - destination by:
Creates new feature branch without checking out
Creates new feature branch and check out
Rebasing (target branch ia a current branch)
Reversing changes: - only local
Adds commits (copies) to current branch in given order
Tagging commits
Merging changes (target branch ia a current branch)
Pulling changes from remote
- in merging way
git pull is equal to git fetch; git merge origin/master
git pull --rebase is equal to git fetch; git rebase origin/master
- Remote tracking (when some branches can be linked by origin/master independently of master branch)
Pushing changes to remote
Removes foo branch in remote
Adds bar branch in local
git log
Moving around in Git: - destination by:
HEAD^
HEAD^^^
HEAD~
HEAD~3
<branch>^
<branch>~2
<branch>
- or by hash of commit:
fed2da64c0efc5293610bdd892f82a58e8cbc5d8
- commands:
git checkout <destination>
git checkout HEAD~;
git checkout HEAD^2;
git checkout HEAD~2;
git checkout HEAD~^2~2
git branch -f <branch> <destination>
git branch <branch> master^~2
- feature in merge commit
git checkout master^1 # goes to the first ancesstor
git checkout master^2 # goes to the second ancesstor
Creates new feature branch without checking out
git branch <feature-branch-name>
git branch <feature-branch-name> HEAD~
Creates new feature branch and check out
git checkout -b branch <feature-branch-name> HEAD~
Rebasing (target branch ia a current branch)
git rebase <source-branch>
- with hash of commit
git rebase <Commit>
- with interactive mode
git rebase -i HEAD~4
- for rebasing target branch with source branch
git rebase <source-branch> <target-branch>
Reversing changes: - only local
git reset HEAD~1
- for share with remote
git revert HEAD
- only for changing last commit message
git commit --amend
Adds commits (copies) to current branch in given order
git cherry-pick <Commit1>, <Commit2>, ...
Tagging commits
git tag <tag-name>
git describe <place>
OUTPUT: <tag>_<numCommits>_g<hash>
Merging changes (target branch ia a current branch)
git merge <source-branch>
Pulling changes from remote
- in merging way
git pull is equal to git fetch; git merge origin/master
git pull
git push
git fetch
git merge origin/master
git push
- in rebase way
git pull --rebase is equal to git fetch; git rebase origin/master
git pull --rebase
git push
git fetch
git rebase origin/master
git push
- when source is related to remote and destination to local (if branch doesn't exist it will be created)
git pull origin <source>:<destination>
git pull origin foo is equal to git fetch origin foo; git merge origin/foo
git pull origin bar~1:bugFix is equal to git fetch origin bar~1:bugFix; git merge bugFix
- Remote tracking (when some branches can be linked by origin/master independently of master branch)
git checkout -b foo origin/master
git pull
git checkout -b foo origin/master
git commit
git push
- when branch exists
git branch -u origin/master foo
git branch -u origin/master
git branch -u foo o/master
git commit
git push
Pushing changes to remote
git push origin <place>
- source is related to local and destination to remote (if branch doesn't exist it will be created)
git push origin <source>:<destination>
git push origin master^^:foo
git push origin foo:master
Removes foo branch in remote
git push origin :foo
Adds bar branch in local
git fetch origin :bar
openssh. Problem with connection to servers via ssh
One of these days I faced the following problem. I needed to organize the ability to work on two computers with servers via ssh. On one machine a public and private key was generated, a config file was configured, everything worked well. Next, I copied the keys to another machine, also set up config file and verified that the key was added ($ ssh-add -l), but when I was trying to connect to any server I was failing. Both machines were on Ubuntu OS (17.10 and 16.04 LTS).
Next, I tried to test connection:
Next, I tried to test connection:
$ ssh -v your-useful.server.comOutput was next:
... debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC:On the last line, the check was froze and ended after a while. After a short searching based on the last line of output, it turned out that problem was associated with a bug in the openssh package. The bug was revealed in the fact that each connection was required to refine the cipher via the -c key.compression: none debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: compression: none debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
$ ssh -c aes256-ctr your-useful.server.comAfter that, everything began to work. To exclude redundancy, you need to add either in /etc/ssh/ssh_config or in ~/.ssh/config (I chose this option) the following line:
Ciphers aes128-ctr,aes192-ctr,aes256-ctr
Ruby. Null-aware operators
1. The safe navigation operator
There are some languages that support object-oriented programming that have support for the so-called the safe navigation operator (SNO). Also it's known as optional chaining operator, safe call operator or null-conditional operator. The SNO is a binary operator that returns null if its first argument is null;
otherwise it returns the second argument.
It's used to avoid sequential explicit null checks and assignments and replace them with method/property chaining. In programming languages where the navigation operator (e.g. ".") leads to an error if applied to a null object, the safe navigation operator stops the evaluation of a method/field chain and returns null as the value of the chain expression. It's currently supported in languages such as Apache Groovy, Ruby, Swift, C#, Kotlin, CoffeeScript and others. There is currently no common naming convention for this operator, but SNO is the most widely used term.
The main advantage of using this operator is that it solves a problem commonly known as pyramid of doom. Instead of writing multiple nested ifs, programmers can just use usual chaining, but put question mark symbols before dots (or other characters used for chaining).
Ruby supports the &. safe navigation operator (also known as the lonely operator) since version 2.3.0
Let's consider concrete example of using safe navigation operator on Ruby. My current version of Ruby is 2.5.1
Let's say that we have two classes: Owner and Account:
Create instances of these classes like that
Now we can get a full information about owner from account by the following way
But what if, while creating instances of our classes, something goes wrong? Then when you try to get the full information about owner from account you won't have guarantees that this operation will be successful. Moreover, we can get an error and our system may fall. Here is an example of such a situation
As result we get next error:
undefined method `summary' for nil:NilClass (NoMethodError)
So, to avoid this, you can use safe navigation operator &.
And instead of an error, we get nil (it's a null in Ruby)
2. The null coalescing operator
The null coalescing operator (called the Logical Defined-Or operator in Perl) is a binary operator that is part of the syntax for a basic conditional expression in several programming languages. While its behavior differs between implementations, the null coalescing operator generally returns the result of its first operand if it exists and isn't null.
In contrast to the ternary conditional if operator used as x ? x : y, but like the binary Elvis operator used as x ?: y, the null coalescing operator is a binary operator and thus evaluates its operands at most once, which is significant if the evaluation of x has side-effects.
In the ruby for these purposes, we can use the operator ||
There are some languages that support object-oriented programming that have support for the so-called the safe navigation operator (SNO). Also it's known as optional chaining operator, safe call operator or null-conditional operator. The SNO is a binary operator that returns null if its first argument is null;
otherwise it returns the second argument.
It's used to avoid sequential explicit null checks and assignments and replace them with method/property chaining. In programming languages where the navigation operator (e.g. ".") leads to an error if applied to a null object, the safe navigation operator stops the evaluation of a method/field chain and returns null as the value of the chain expression. It's currently supported in languages such as Apache Groovy, Ruby, Swift, C#, Kotlin, CoffeeScript and others. There is currently no common naming convention for this operator, but SNO is the most widely used term.
The main advantage of using this operator is that it solves a problem commonly known as pyramid of doom. Instead of writing multiple nested ifs, programmers can just use usual chaining, but put question mark symbols before dots (or other characters used for chaining).
Ruby supports the &. safe navigation operator (also known as the lonely operator) since version 2.3.0
Let's consider concrete example of using safe navigation operator on Ruby. My current version of Ruby is 2.5.1
Let's say that we have two classes: Owner and Account:
class Owner
attr_accessor :first_name, :last_name, :age
def initialize(first_name:, last_name:, age:)
self.first_name = first_name
self.last_name = last_name
self.age = age
end
def summary
"Owner: first name: #{first_name}, last name: #{last_name}, age: #{age}"
end
end
module Roles
GUEST = 1
USER = 2
ADMIN = 4
end
class Account
include Roles
attr_accessor :owner, :role
def initialize(owner, role = GUEST)
self.owner = owner
self.role = role
end
end
Create instances of these classes like that
owner = Owner.new(
first_name: 'John',
last_name: 'Smith',
age: 30
)
account = Account.new(owner, Roles::USER)
Now we can get a full information about owner from account by the following way
puts account.owner.summary
But what if, while creating instances of our classes, something goes wrong? Then when you try to get the full information about owner from account you won't have guarantees that this operation will be successful. Moreover, we can get an error and our system may fall. Here is an example of such a situation
account = Account.new(nil)
puts account.owner.summary
As result we get next error:
undefined method `summary' for nil:NilClass (NoMethodError)
So, to avoid this, you can use safe navigation operator &.
puts account&.owner&.summary
And instead of an error, we get nil (it's a null in Ruby)
2. The null coalescing operator
The null coalescing operator (called the Logical Defined-Or operator in Perl) is a binary operator that is part of the syntax for a basic conditional expression in several programming languages. While its behavior differs between implementations, the null coalescing operator generally returns the result of its first operand if it exists and isn't null.
In contrast to the ternary conditional if operator used as x ? x : y, but like the binary Elvis operator used as x ?: y, the null coalescing operator is a binary operator and thus evaluates its operands at most once, which is significant if the evaluation of x has side-effects.
In the ruby for these purposes, we can use the operator ||
some_variable = nil || 'default_value'
Git. Work with Bitbucket/GitHub repositories without username/password
Initially, you should have two generated keys: private - id_rsa and public - id_rsa.pub.
To do this, you need to run the command:
Next, you need to add your public key (its contents) via the web interface.
After that, you can work with your repositories without having to enter a password for every action you take.
But it's important to remember that you must work through ssh:// not through https://
If initially you cloned your repository like this
then you need to change the remote URL to ssh://
To do this, run the command:
To look at current remote URL it's possible either that
or that
To do this, you need to run the command:
$ ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/id_rsa
Next, you need to add your public key (its contents) via the web interface.
After that, you can work with your repositories without having to enter a password for every action you take.
But it's important to remember that you must work through ssh:// not through https://
If initially you cloned your repository like this
$ git clone https://git@REPOSITORY.git
then you need to change the remote URL to ssh://
To do this, run the command:
$ git remote set-url origin ssh://git@REPOSITORY.git
To look at current remote URL it's possible either that
$ git remote -v
or that
$ git config remote.origin.url
Subscribe to:
Posts
(
Atom
)

