How to run an Elixir escript on Windows 8.1 - windows

I'm creating a mix escript, and all seems well, but I can't invoke the generated escript executable.
>mix escript.build
lib/cmdlineutil.ex:2: warning: variable args is unused
Compiled lib/cmdlineutil.ex
Generated cmdlineutil.app
Consolidated Access
Consolidated Collectable
Consolidated Enumerable
Consolidated Inspect
Consolidated List.Chars
Consolidated Range.Iterator
Consolidated String.Chars
Consolidated protocols written to _build/dev/consolidated
Generated escript cmdlineutil with MIX_ENV=dev
>cmdlineutil
'cmdlineutil' is not recognized as an internal or external command,
operable program or batch file.
>mv cmdlineutil cmdlineutil.exe
>cmdlineutil.exe
This version of C:\Git\elixir\cmdlineutil\cmdlineutil.exe is not
compatible with the version of Windows that you're running. Check your
computer's system information and then contact the software publisher.
Message box:
Unsupported 16-Bit Application
The program or feature "\??\C:\Git\elixir\cmdlineutil\cmdlineutil.exe"
cannot start or run due to incompatibility with 64-bit versions of
Windows. Please contact the software vendor to ask if a 64-bit
Windows compatible version is available.
lib\cmdlineutil.ex:
defmodule CmdLineUtil.Echo do
def main(args) do
IO.puts "Hello!"
end
end
mix.exs:
defmodule CmdLineUtil.Echo.Mixfile do
use Mix.Project
def project do
[app: :cmdlineutil,
version: "0.0.1",
elixir: "~> 1.0.0",
escript: escript,
deps: deps]
end
def escript do
[main_module: CmdLineUtil.Echo]
end
# Configuration for the OTP application
#
# Type `mix help compile.app` for more information
def application do
[applications: [:logger]]
end
# Dependencies can be Hex packages:
#
# {:mydep, "~> 0.3.0"}
#
# Or git/path repositories:
#
# {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
#
# Type `mix help deps` for more examples and options
defp deps do
[]
end
end

Theres an escript command installed with Erlang.
>escript cmdlineutil

Related

How to configure Steep to find RBS files for a gem outside the stdlib?

Cannot find type `Sinatra::Base`
ruby file
class StaticApp < Sinatra::Base
end
rbs file
class StaticApp < Sinatra::Base
end
run
bundle exec steep check --log-level=fatal
result
[error] Cannot find type `Sinatra::Base`
Diagnostic ID: RBS::UnknownTypeName
I use steep gem. It seems it is needed to require some files. But
library 'sinatra'
doesn't work.
#<RBS::EnvironmentLoader::UnknownLibraryError: Cannot find type definitions for library: sinatra ([nil])>
What do I wrong?
Thanks.
But library 'sinatra' doesn't work ..
RBS::EnvironmentLoader::UnknownLibraryError
Short answer
# Steepfile
target :app do
repo_path 'vendor/rbs'
Create a directory structure like vendor/rbs/sinatra/0/sinatra.rbs.
How you write or generate the contents of sinatra.rbs is out of the scope of this answer, but check out:
rbs collection
gem_rbs_collection
rbs_rails
Long answer
Steep is using an RBS::EnvironmentLoader.
# steep-0.47.0/lib/steep/project/target.rb:54
loader = RBS::EnvironmentLoader.new(core_root: core_root_path, repository: repo)
options.libraries.each do |lib|
name, version = lib.split(/:/, 2)
loader.add(library: name, version: version)
end
The EnvironmentLoader can find a library in either gem_sig_path (I think this would be a sig folder distributed in the gem), or in a repository.
# rbs-1.7.1/lib/rbs/environment_loader.rb:68
def has_library?(library:, version:)
if self.class.gem_sig_path(library, version) || repository.lookup(library, version)
true
else
false
end
end
In a Steepfile, repositories are configured via repo_path.
# Steepfile
repo_path 'vendor/rbs'
For the directory structure of a repository, I took https://github.com/ruby/rbs/tree/master/stdlib as an example.
ls -R vendor/rbs
activesupport
vendor/rbs/activesupport:
0
vendor/rbs/activesupport/0:
activesupport.rbs

How to read the gem file specifications from extconf.rb?

I'm building a Ruby gem file that has various 3rd party executable requirements (some non-ruby tools that the gem will then use through system calls).
The requirement list is specified using the gemspec informative requirements list, and I was tasked with creating a set up where that requirement list is verified during installation - essentially converting the requirements list from being informative to being authoritative.
My initial approach is to use extensions, like in the extconf.rb pattern, to run some ruby code during installation that will verify the list of requirements and fail the installation if the requirements are not met.
So my current implementation is using a ext/Rakefile, that reads gemspec file using a hard-coded path, parses the requirements list using a custom (but straight-forward and simple) syntax and run some simple tests on the required executables.
I would really want to factor out the dependency on knowing the path to the gemspec file, so I can reuse the code in a modular way on other projects.
For completion (and in the hopes that it will be useful for someone), here's my code - which uses the Gem::Ext::Builder "Rakefile mode" to just run some arbitrary code.
require 'rubygems'
require 'mkmf'
def verify_requirement(reqspec)
exe, version_spec, version_regex = reqspec.split(/\s*,\s*/,3)
exe = $1 if exe =~ /\[([^\]]+)\]/ # support human readable alias for executable name
abort "Missing required executable #{exe}!" unless find_executable(exe)
return unless version_spec # no version is specified, so executable existing is good enough
version = %x|#{exe} --version 2>&1|.chomp
version = %x|#{exe} -version 2>&1|.chomp unless $?.success?
abort "Error checking for version of #{exe}: (#{$?.exitstatus}) #{version}" unless $?.success?
if version_regex
abort "Version test '#{version_regex}' failed to match '#{version}'!" unless version =~ /#{version_regex}/m
abort "Version test '#{version_regex}' failed to generate a version number!" unless $1
version = $1
end
abort "Failed to locate a valid version number for #{exe}, found '#{version}'" unless version =~ /^[0-9\.]+/
abort "Insufficient version '#{version}' for #{exe} - requires #{version_spec}" unless Gem::Dependency.new(exe, version_spec).match? exe, version
end
task :default do
gemspec = File.absolute_path('../my.gemspec')
Gem::Specification::load(gemspec).requirements.each do |req|
verify_requirement(req)
end
end
This code requires that the requirements uses either of these syntaxes:
exe-file[, <semantic-version-spec>[, <version-garabbing-regex>]]
alias '[' exe-file ']'[, <semantic-version-spec>[, <version-garabbing-regex>]]
For example:
spec.requirements << 'sox'
spec.requirements << 'ffmpeg, >= 2.5, ffmpeg version ([\d\.]+)'
spec.requirements << 'ImageMagick [convert], >= 6.7.5, ImageMagick ([\d\.]+)'
The Gem::Specification class can be used to load and parse the gemspec. I'm using the following code in ext/Rakefile to perform tasks based on the gemspec file:
task :default do
gemspec = File.absolute_path('../gemname.gemspec')
Gem::Specification::load(gemspec).requirements.each do |req|
verify_requirement(req)
end
end

Ruby Gem: Install configuration files to the user-home directory

I have to make a REST-Client in Ruby.
The client must be runnable from the command-line like a binary and also it must be "requirable" in a ruby script and provide different functions.
My gemspec does exactly what it should.
But i have no idea how to install a configuration file (YAML) in the user-home folder?
The config file should be in the user directory to provide easy access for the user.
Is this even possible?
Should i check on the first run if there is a config file and create it?
Can i execute an own installation routine while installing a gem?
I did exactly the same thing in Python and it worked fine, so the Ruby client should behave similar.
For such decisions, I wrote gem persey. If you look at the description of the use of this gem, you can see that it provides what you expect:
# Rails.root are not initialized here
app_path = File.expand_path('../../', __FILE__)
# ...
# config with secret keys
# you don't want store this config in repository and copy to secret folder on host machine
my_secret_key_config = '/home/user/secret/keys.yml'
# ...
# Persey.init ENV["environment"] do # set current environment
Persey.init Rails.env do # set current environment
source :yaml, my_secret_key_config, :secret # no comments. It's secret!
env :production do
# ...
end
env :development, :parent => :production do
# ...
end
end

Creating Ruby Main (command line utility) program with multiple files

I am trying to use the main gem for making command line utilities. This was presented in a recent Ruby Rogues podcast.
If I put all the code in one file and require that file, then rspec gives me an error, as the main dsl regards rpsec as a command line invocation of the main utility.
I can break out a method into a new file and have rspec require that file. Suppose you have this program, but want to put the do_something method in a separate file to test with rspec:
require 'main'
def do_something(foo)
puts "foo is #{foo}"
end
Main {
argument('foo'){
required # this is the default
cast :int # value cast to Fixnum
validate{|foo| foo == 42} # raises error in failure case
description 'the foo param' # shown in --help
}
do_something(arguments['foo'].value)
}
What is the convenient way to distribute/deploy a ruby command line program with multiple files? Maybe create a gem?
You are on the right track for testing - basically you want your "logic" in separate files so you can unit test them. You can then use something like Aruba to do an integration test.
With multiple files, your best bet is to distribute it as a RubyGem. There's lots of resources out there, but the gist of it is:
Put your executable in bin
Put your files in lib/YOUR_APP/whatever.rb where "YOUR_APP" is the name of your app. I'd also recommend namespacing your classes with modules named for your app
In your executable, require the files in lib as if lib were in the load path
In your gemspec, make sure to indicate what your bin files are and what your lib files are (if you generate it with bundle gem and are using git, you should be good to go)
This way, your app will have access to the files in lib at runtime, when installed with RubyGems. In development, you will need to either do bundle exec bin/my_app or RUBYLIB=lib bin/my_app. Point is, RubyGems takes care of the load path at runtime, but not at development time.

Setting up rake-pipeline for use with handlebars alongside Google App Engine

So here's what I'm attempting to do. I'm building an ember.js application, with a java backend running on GAE.
I'm using handlebars, but I want them divided up into separate files, not just all pasted into the index.html.
Via the ember.js irc I was turned on to rake-pipeline along with minispade
Along with the web filters and a custom handlebars filter I started building the assetfile. I don't know Ruby, or gem files, etc.
So I'm trying to figure out the best way to be able to compile my coffeescript/handlebars files on the fly, minispade them, but keep the individual files accessible while in dev mode so I can debug them. What makes that hard is that the rake pipeline is running on a different port than GAE. So I'm not sure exactly how to handle this. Do I make my index file in GAE point to individual files at the 9292 port (rakep) during development, but in production mode point to the fully concatenated version? I'm not sure.
So I was attempting to do that here: https://gist.github.com/1495740 by having only one section that was triggered by the 'build' flag. Not even sure if that works that way.
I know there's a lot of confusion here. Apologies, like I said I'm not even remotely familiar with the Ruby style of doing things.
Since you're not a Ruby person, here are the most reliable steps for getting a stock OSX environment set up with rake pipeline:
Step 1: Install bundler
# on OSX, using built-in Ruby
$ sudo gem install bundler --pre
Step 2: Create a Gemfile
# inside your app directory
$ bundle init
# will create a file named Gemfile in the root
Step 3: Add rake-pipeline to the Gemfile
# inside the Gemfile
gem "rake-pipeline-web-filters"
Step 4: Install your gems
$ bundle install --binstubs
Step 5: Set up Assetfile
However you were already doing it...
Step 6: Run Rake::Pipeline
# to run the preview server
$ bin/rakep
# to build your assets
$ bin/rakep build
Rake::Pipeline.build is the method that evaluates an Assetfile. You can imagine that your entire Assetfile is wrapped inside a Rake::Pipeline.build {} block; you shouldn't ever need to write one inside an Assetfile.
Some of the filters in the docs are hypothetical, most of those docs were written before there were any filters at all. A CoffeeScript compiler has been recently added, though.
As to your main question, I'm not sure there's a clean way to do it with the current rakep implementation. An Assetfile is just Ruby, though, so it's possible to hack something together that should work. Here's how I would write yours:
require "json"
require "rake-pipeline-web-filters"
require "rake-pipeline-web-filters/helpers"
class HandlebarsFilter < Rake::Pipeline::Filter
def initialize(&block)
block ||= proc { |input| input.sub(/\.handlebars$/, '.js') }
super(&block)
end
def generate_output(inputs, output)
inputs.each do |input|
output.write "return Ember.Handlebars.compile(#{input.read.to_json})"
end
end
end
# process all js, css and html files in app/assets
input "assets"
# processed files should be outputted to public
output "public"
# process all coffee files
match "**/*.coffee" do
# compile all CoffeeScript files. the output file
# for the compilation should be the input name
# with the .coffee extension replaced with .js
coffee_script
# The coffee_script helper is exactly equivalent to:
# filter Rake::Pipeline::Web::Filters::CoffeeScriptCompiler
end
match "**/*.js" do
minispade
if ENV['RAKEP_ENV'] == "production"
concat "application.js"
else
concat
end
end
match "**/*.handlebars" do
filter HandlebarsFilter
minispade
concat "templates.js"
end
The if ENV['RAKEP_ENV'] bit reads an environment variable to decide whether to concatenate your JS to a single file.
So now you can run RAKEP_ENV="production" rakep build for a concatenated build, or just rakep build for a development build.

Resources