Compare commits

..

62 Commits

Author SHA1 Message Date
Adam Roben
6b41059cdf Merge pull request #1696 from github/cut-release-v3.5.1
Bump to 3.5.1
2014-11-10 15:19:28 -05:00
Adam Roben
62cb42eee5 Bump to 3.5.1 2014-11-10 15:15:15 -05:00
Adam Roben
6bbb56db00 Merge pull request #1695 from github/nil-safety
Make it safe to pass nil to Language.find_by_name/alias again
2014-11-10 15:13:28 -05:00
Adam Roben
160598b9ef Make it safe to pass nil to Language.find_by_name/alias again
This restores compatibility with v3.4.x.
2014-11-10 15:12:29 -05:00
Adam Roben
32b07a4e10 Merge pull request #1694 from github/cut-release-v3.5.0
Bumping to 3.5.0
2014-11-10 14:52:55 -05:00
Adam Roben
8890c57681 Bumping to 3.5.0 2014-11-10 14:38:55 -05:00
Adam Roben
de188126fb Merge pull request #1683 from github/find-by-ext
Extract Language.find_by_extension
2014-11-10 14:37:45 -05:00
Adam Roben
97a1adcef1 Allow extensions without a leading dot
This makes the API a little easier to use.
2014-11-10 14:30:37 -05:00
Adam Roben
ffbe95d6e5 Fix docs 2014-11-10 14:15:21 -05:00
Adam Roben
d54f86ae58 Add some tests for Language.find_by_extension 2014-11-10 14:12:29 -05:00
Brandon Keepers
92ace440b9 Merge pull request #1540 from rlespinasse/golo-support
Add support for Golo language
2014-11-08 14:00:36 -05:00
Adam Roben
d5ee477d3b Merge pull request #1687 from github/shell-session-scope
Add a TextMate scope for .sh-session files
2014-11-07 15:47:35 -05:00
Adam Roben
6e8152c423 Add a TextMate scope for .sh-session files
Coming soon to Atom. See https://github.com/atom/language-shellscript/pull/3
2014-11-07 15:02:37 -05:00
Adam Roben
8149356668 Merge pull request #1678 from tenbits/master
Use MaskLexer for *.mask
2014-11-07 13:39:24 -05:00
Alex Kit
806e30d70f Use MaskLexer for *.mask 2014-11-07 19:26:37 +01:00
Adam Roben
299ec8f8ea Merge pull request #1686 from github/pytb-tm_scope
Add a TextMate scope for .pytb files
2014-11-07 12:57:36 -05:00
Adam Roben
f6fbd18bd5 Add a TextMate scope for .pytb files
This is the scope that Atom uses for these files.
See https://github.com/atom/language-python/blob/master/grammars/python-traceback.cson
2014-11-07 12:55:59 -05:00
Adam Roben
ecd30d3ccf Merge pull request #1675 from github/more-aliases
Pull in aliases and file extensions from Pygments
2014-11-07 10:31:00 -05:00
Brandon Keepers
228d89649a Add Language.find_by_extension 2014-11-07 10:27:07 -05:00
Adam Roben
751360ecf1 Make Language.[] and Language.find_by(alias|name) ignore case
This makes it easier to find a Linguist::Language for a fenced code
block in Markdown, where language names are often specified in
lowercase.
2014-11-07 10:09:55 -05:00
Adam Roben
d9ed216092 Add language aliases from Pygments
I went through all the aliases Pygments supports and removed the ones
that could already be used to find a Linguist::Language. Then I found
the Pygments::Lexer associated with each alias and found an associated
Linguist::Language for it (looking for a language with the same name as
the lexer, or by looking for the first langauge that uses that lexer).
Then I added the alias to the language's alias list.
2014-11-06 16:48:52 -05:00
Adam Roben
18a3ef9e5e Pull in file extensions from Pygments
I read all the file extensions that Pygments knows about, mapped them
back to the appropriate Linguist::Language, and added them to the
languages.yaml file.
2014-11-06 16:43:08 -05:00
Arfon Smith
e7b670c5de Merge pull request #1669 from github/support-hack
Support hack
2014-11-05 13:56:37 -06:00
Arfon Smith
114fabd29a Test for Hack heuristic 2014-11-04 16:12:46 -06:00
Arfon Smith
0946791434 Merge branch 'master' into support-hack
Conflicts:
	lib/linguist/heuristics.rb
2014-11-04 16:09:00 -06:00
Brandon Keepers
06bcdba9c4 Merge pull request #1654 from danijar/master
Exclude minified JavaScript and CSS
2014-11-03 14:20:59 -05:00
Danijar Hafner
1dbbcb73e7 Add tests for minified JavaScript and CSS
Also, exclude -min.css pattern, like already done for JavaScript files
2014-11-03 19:41:31 +01:00
Arfon Smith
f2cd75332c Merge pull request #1660 from github/1623-local
1623 local
2014-11-02 20:17:38 -06:00
Arfon Smith
2cd7579e21 Merge branch '1623-local' of github.com:github/linguist into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:14:46 -06:00
Arfon Smith
d9daae176e Merge branch 'master' into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:13:58 -06:00
Arfon Smith
20814ec533 Merge branch 'master' into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:12:59 -06:00
Arfon Smith
9d8ab16a38 Merge branch 'master' into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:11:49 -06:00
Arfon Smith
49c2793bf5 Syntax preference 2014-11-02 19:56:20 -06:00
Danijar Hafner
20aee11cea Exclude minified JavaScript and CSS
Those files are either external libraries or builds of the repository itself. In any case they are generated automatically and shouldn't count in the language statistics. This also simplifies some of the rules that had to exclude both minified and normal dependencies.
2014-11-01 19:13:19 +01:00
Arfon Smith
e8cf750e18 Merge pull request #1639 from pchaigno/asc
Heuristic rule to detect AsciiDoc files
2014-11-01 09:26:49 -05:00
Brandon Keepers
21f56744d4 Merge pull request #1608 from github/just-yajl
Use yajl since it is already a dependency
2014-10-31 18:03:28 -04:00
Brandon Keepers
02aeb4f895 Merge remote-tracking branch 'origin/master' into just-yajl
* origin/master: (42 commits)
  its always greener
  that new green shell
  Removing stale extension
  Update README.md
  Add moon interpreter for MoonScript
  Bumping version for 3.4.1 release
  Use text.html.erb scope for HTML+ERB files
  Add sample .dyalog file for file type APL
  Added extra Papyrus sample files.
  Add sample Papyrus script
  Add Papyrus support
  Add LOLCODE support
  Add ProGuard config files to vendored files
  Recognise *.dyalog as APL sources
  Assign a bunch more TextMate scopes
  CI step for samples
  Add .command as a Shell file extension
  CI config
  Vendored gems
  Update cibuild
  ...

Conflicts:
	Rakefile
2014-10-31 18:03:03 -04:00
Arfon Smith
f9de16fbd2 Merge pull request #1620 from unfunco/ant-build-dist-support
Add build.xml.dist to XML filenames
2014-10-31 16:46:49 -05:00
Brandon Keepers
abe002f30c Merge remote-tracking branch 'origin/master' into tricknotes-ruby-22
* origin/master: (51 commits)
  its always greener
  that new green shell
  Removing stale extension
  Update README.md
  Add moon interpreter for MoonScript
  Bumping version for 3.4.1 release
  Use text.html.erb scope for HTML+ERB files
  Add sample .dyalog file for file type APL
  Added extra Papyrus sample files.
  Add sample Papyrus script
  Add Papyrus support
  Add LOLCODE support
  Add ProGuard config files to vendored files
  Recognise *.dyalog as APL sources
  Assign a bunch more TextMate scopes
  CI step for samples
  Add .command as a Shell file extension
  CI config
  Vendored gems
  Update cibuild
  ...

Conflicts:
	Gemfile
2014-10-31 17:36:06 -04:00
Jessica Lord
e5ae6fb00d Merge pull request #1650 from github/greenshell
That new green shell, fixes #1640
2014-10-31 21:16:34 +00:00
Jessica Lord
a0a8dd8897 its always greener 2014-10-31 21:15:59 +00:00
Jessica Lord
e00f073726 that new green shell 2014-10-31 20:08:25 +00:00
Arfon Smith
1a9ee8e187 Merge pull request #1636 from Verteiron/master
Add support for Papyrus scripts
2014-10-30 06:24:56 -05:00
Arfon Smith
213fce00e0 Merge pull request #1646 from github/gradle-extension
Removing stale extension
2014-10-29 19:57:32 -05:00
Arfon Smith
380739b209 Removing stale extension 2014-10-29 19:56:59 -05:00
Arfon Smith
36322f8ac0 Update README.md 2014-10-29 19:38:19 -05:00
Arfon Smith
57d1ec7733 Merge pull request #1645 from pchaigno/moon-shebang
Add moon interpreter for MoonScript
2014-10-29 17:10:14 -05:00
Paul Chaignon
648c6d4547 Add moon interpreter for MoonScript 2014-10-29 15:00:21 -04:00
Paul Chaignon
ebabcfc84f Heuristic rule to detect AsciiDoc files 2014-10-27 10:50:18 -04:00
Verteiron
5f22bf225c Added extra Papyrus sample files. 2014-10-26 15:30:40 -05:00
Verteiron
8eee8ad9cf Add sample Papyrus script
This is the metaquest script from one of my own mods.
2014-10-26 14:58:17 -05:00
Verteiron
24743985e4 Add Papyrus support
Papyrus is a scripting language used by mods/plugins for The Elder Scrolls V: Skyrim.
2014-10-26 14:53:20 -05:00
Paul Chaignon
fd707ddf7e Heuristic rules to distinguish .sc files between SuperCollider and Scala 2014-10-23 14:22:12 -04:00
Paul Chaignon
b6a9993c97 Add .sc as a SuperCollider file extension 2014-10-22 10:16:30 -04:00
Josh Watzman
9c044c5bd0 Add detection for Hack files with ".php" file extension
Based on top of PR#1447. Adds a simple heuristic check for Hack files vs PHP files (`<?hh` vs other `<?`).

Tested by verifying that the Hack example site was detected as 100% Hack and that Laravel was detected as 100% PHP. (Without the heuristic, Laravel gets detected as about 50% Hack, just by randomness in the classifier since PHP and Hack are very hard to distinguish unless you actually parse the file and look for specific language features.)
2014-10-21 16:17:58 -07:00
Josh Watzman
b2cb74cabf Add detection for Hack files with ".hh" file extension
Hack is Facebook's dialect of PHP: http://hacklang.org/. This adds support for detecting it via the ".hh" file extension; although that extension techincally conflicts with C++ headers, the files look different enough that the existing classifier based on sample code has no trouble distinguising them.

This diff deliberately does not deal with detecting ".php" as another valid extension for Hack code. That's much trickier since the code looks basically identical to PHP to the classifier, and needs a different approach.
2014-10-21 15:35:57 -07:00
Daniel Morris
6f8278aa79 Add build.xml.dist to XML filenames 2014-10-21 10:21:39 +01:00
Brandon Keepers
cd743332f4 Use yajl since it is already a dependency
Both JSON and Yajl were listed as dependencies. Pygments.rb already requires yajl, so let's just use that instead of using both.
2014-10-17 14:45:28 -04:00
Ryunosuke SATO
a1884ca261 Run test against Ruby 2.2 on Travis CI 2014-10-15 00:54:00 +09:00
Ryunosuke SATO
e452291314 Run test against latest Ruby 2.1 on Travis CI
see: https://twitter.com/travisci/status/513233940442644480
2014-10-15 00:53:57 +09:00
Romain Lespinasse
ce1e2441f4 Choose a color from the Golo logo 2014-10-11 10:27:06 +02:00
Romain Lespinasse
5a59ecbc2a Add support for Golo language 2014-09-17 13:59:02 +02:00
78 changed files with 3745 additions and 59 deletions

View File

@@ -6,6 +6,7 @@ before_install:
rvm:
- 1.9.3
- 2.0.0
- 2.1.1
- 2.1
- 2.2
notifications:
disabled: true

View File

@@ -1,2 +1,3 @@
source 'https://rubygems.org'
gemspec
gem 'test-unit', require: false if RUBY_VERSION >= '2.2'

View File

@@ -108,6 +108,8 @@ See [Linguist::Generated#generated?](https://github.com/github/linguist/blob/mas
Linguist supports custom overrides for language definitions and vendored paths. Add a `.gitattributes` file to your project using the keys `linguist-language` and `linguist-vendored` with the standard git-style path matchers for the files you want to override.
Please note that the overrides currently only affect the language statistics for a repository and not the syntax-highlighting of files.
```
$ cat .gitattributes
*.rb linguist-language=Java

View File

@@ -1,8 +1,8 @@
require 'bundler/setup'
require 'json'
require 'rake/clean'
require 'rake/testtask'
require 'yaml'
require 'yajl'
task :default => :test
@@ -20,15 +20,13 @@ end
task :samples do
require 'linguist/samples'
require 'yajl'
data = Linguist::Samples.data
json = Yajl::Encoder.encode(data, :pretty => true)
File.open('lib/linguist/samples.json', 'w') { |io| io.write json }
json = Yajl.dump(Linguist::Samples.data, :pretty => true)
File.write 'lib/linguist/samples.json', json
end
task :build_gem => :samples do
languages = YAML.load_file("lib/linguist/languages.yml")
File.write("lib/linguist/languages.json", JSON.dump(languages))
File.write("lib/linguist/languages.json", Yajl.dump(languages))
`gem build github-linguist.gemspec`
File.delete("lib/linguist/languages.json")
end
@@ -72,11 +70,11 @@ namespace :benchmark do
reference_file = ENV["REFERENCE"]
candidate_file = ENV["CANDIDATE"]
reference = JSON.parse(File.read(reference_file))
reference = Yajl.load(File.read(reference_file))
reference_counts = Hash.new(0)
reference.each { |filename, language| reference_counts[language] += 1 }
candidate = JSON.parse(File.read(candidate_file))
candidate = Yajl.load(File.read(candidate_file))
candidate_counts = Hash.new(0)
candidate.each { |filename, language| candidate_counts[language] += 1 }
@@ -126,14 +124,12 @@ namespace :classifier do
def each_public_gist
require 'open-uri'
require 'json'
url = "https://api.github.com/gists/public"
loop do
resp = open(url)
url = resp.meta['link'][/<([^>]+)>; rel="next"/, 1]
gists = JSON.parse(resp.read)
gists = Yajl.load(resp.read)
for gist in gists
for filename, attrs in gist['files']

View File

@@ -19,7 +19,6 @@ Gem::Specification.new do |s|
s.add_dependency 'pygments.rb', '~> 0.6.0'
s.add_dependency 'rugged', '~> 0.21.1b2'
s.add_development_dependency 'json'
s.add_development_dependency 'mocha'
s.add_development_dependency 'pry'
s.add_development_dependency 'rake'

View File

@@ -25,6 +25,15 @@ module Linguist
if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) }
result = disambiguate_cl(data, languages)
end
if languages.all? { |l| ["Hack", "PHP"].include?(l) }
result = disambiguate_hack(data, languages)
end
if languages.all? { |l| ["Scala", "SuperCollider"].include?(l) }
result = disambiguate_sc(data, languages)
end
if languages.all? { |l| ["AsciiDoc", "AGS Script"].include?(l) }
result = disambiguate_asc(data, languages)
end
return result
end
end
@@ -88,6 +97,33 @@ module Linguist
matches
end
def self.disambiguate_hack(data, languages)
matches = []
if data.include?("<?hh")
matches << Language["Hack"]
elsif /<?[^h]/.match(data)
matches << Language["PHP"]
end
matches
end
def self.disambiguate_sc(data, languages)
matches = []
if (/\^(this|super)\./.match(data) || /^\s*(\+|\*)\s*\w+\s*{/.match(data) || /^\s*~\w+\s*=\./.match(data))
matches << Language["SuperCollider"]
end
if (/^\s*import (scala|java)\./.match(data) || /^\s*val\s+\w+\s*=/.match(data) || /^\s*class\b/.match(data))
matches << Language["Scala"]
end
matches
end
def self.disambiguate_asc(data, languages)
matches = []
matches << Language["AsciiDoc"] if /^=+(\s|\n)/.match(data)
matches
end
def self.active?
!!ACTIVE
end

View File

@@ -2,7 +2,7 @@ require 'escape_utils'
require 'pygments'
require 'yaml'
begin
require 'json'
require 'yajl'
rescue LoadError
end
@@ -62,7 +62,7 @@ module Linguist
end
# Language name index
@index[language.name] = @name_index[language.name] = language
@index[language.name.downcase] = @name_index[language.name.downcase] = language
language.aliases.each do |name|
# All Language aliases should be unique. Raise if there is a duplicate.
@@ -70,7 +70,7 @@ module Linguist
raise ArgumentError, "Duplicate alias: #{name}"
end
@index[name] = @alias_index[name] = language
@index[name.downcase] = @alias_index[name.downcase] = language
end
language.extensions.each do |extension|
@@ -164,7 +164,7 @@ module Linguist
#
# Returns the Language or nil if none was found.
def self.find_by_name(name)
@name_index[name]
name && @name_index[name.downcase]
end
# Public: Look up Language by one of its aliases.
@@ -178,7 +178,7 @@ module Linguist
#
# Returns the Lexer or nil if none was found.
def self.find_by_alias(name)
@alias_index[name]
name && @alias_index[name.downcase]
end
# Public: Look up Languages by filename.
@@ -194,9 +194,25 @@ module Linguist
def self.find_by_filename(filename)
basename = File.basename(filename)
extname = FileBlob.new(filename).extension
langs = @filename_index[basename] +
@extension_index[extname]
langs.compact.uniq
(@filename_index[basename] + find_by_extension(extname)).compact.uniq
end
# Public: Look up Languages by file extension.
#
# extname - The extension String.
#
# Examples
#
# Language.find_by_extension('.rb')
# # => [#<Language name="Ruby">]
#
# Language.find_by_extension('rb')
# # => [#<Language name="Ruby">]
#
# Returns all matching Languages or [] if none were found.
def self.find_by_extension(extname)
extname = ".#{extname}" unless extname.start_with?(".")
@extension_index[extname]
end
# Public: Look up Languages by shebang line.
@@ -227,7 +243,7 @@ module Linguist
#
# Returns the Language or nil if none was found.
def self.[](name)
@index[name]
name && @index[name.downcase]
end
# Public: A List of popular languages
@@ -533,8 +549,8 @@ module Linguist
languages_yml = File.expand_path("../languages.yml", __FILE__)
languages_json = File.expand_path("../languages.json", __FILE__)
if File.exist?(languages_json) && defined?(JSON)
languages = JSON.load(File.read(languages_json))
if File.exist?(languages_json) && defined?(Yajl)
languages = Yajl.load(File.read(languages_json))
else
languages = YAML.load_file(languages_yml)
end

View File

@@ -90,6 +90,8 @@ ActionScript:
color: "#e3491a"
search_term: as3
aliases:
- actionscript 3
- actionscript3
- as3
extensions:
- .as
@@ -99,7 +101,10 @@ Ada:
color: "#02f88c"
extensions:
- .adb
- .ada
- .ads
aliases:
- ada95ada2005
Agda:
type: programming
@@ -117,9 +122,11 @@ Alloy:
ApacheConf:
type: markup
aliases:
- aconf
- apache
extensions:
- .apacheconf
- .conf
tm_scope: source.apache-config
Apex:
@@ -180,6 +187,7 @@ Assembly:
- nasm
extensions:
- .asm
- .ASM
- .a51
tm_scope: source.asm.x86
@@ -196,6 +204,7 @@ AutoHotkey:
- ahk
extensions:
- .ahk
- .ahkl
AutoIt:
type: programming
@@ -229,6 +238,9 @@ Batchfile:
search_term: bat
aliases:
- bat
- batch
- dosbatch
- winbatch
extensions:
- .bat
- .cmd
@@ -241,8 +253,10 @@ Befunge:
BlitzBasic:
type: programming
aliases:
- blitzplus
- b3d
- blitz3d
- blitzplus
- bplus
extensions:
- .bb
- .decls
@@ -253,6 +267,8 @@ BlitzMax:
color: "#cd6400"
extensions:
- .bmx
aliases:
- bmax
Bluespec:
type: programming
@@ -291,6 +307,7 @@ C:
- .c
- .cats
- .h
- .idc
- .w
C#:
@@ -316,19 +333,20 @@ C++:
extensions:
- .cpp
- .C
- .CPP
- .H
- .c++
- .cc
- .cxx
- .H
- .h
- .h++
- .hh
- .hpp
- .hxx
- .inl
- .ipp
- .tcc
- .tpp
- .ipp
C-ObjDump:
type: data
@@ -364,6 +382,8 @@ COBOL:
type: programming
extensions:
- .cob
- .COB
- .CPY
- .cbl
- .ccp
- .cobol
@@ -455,8 +475,10 @@ ColdFusion:
aliases:
- cfm
- cfml
- coldfusion html
extensions:
- .cfm
- .cfml
tm_scope: text.html.cfm
ColdFusion CFC:
@@ -500,6 +522,9 @@ Component Pascal:
- .cp
- .cps
tm_scope: source.pascal
aliases:
- delphi
- objectpascal
Coq:
type: programming
@@ -512,9 +537,13 @@ Cpp-ObjDump:
lexer: cpp-objdump
extensions:
- .cppobjdump
- .c++-objdump
- .c++objdump
- .cpp-objdump
- .cxx-objdump
tm_scope: objdump.x86asm
aliases:
- c++-objdumb
Creole:
type: prose
@@ -536,6 +565,8 @@ Cucumber:
extensions:
- .feature
tm_scope: text.gherkin.feature
aliases:
- gherkin
Cuda:
type: programming
@@ -559,6 +590,8 @@ Cython:
- .pyx
- .pxd
- .pxi
aliases:
- pyrex
D:
type: programming
@@ -609,6 +642,8 @@ Diff:
extensions:
- .diff
- .patch
aliases:
- udiff
Dogescript:
type: programming
@@ -622,6 +657,7 @@ Dylan:
color: "#3ebc27"
extensions:
- .dylan
- .dyl
- .intr
- .lid
@@ -706,6 +742,7 @@ Erlang:
color: "#0faf8d"
extensions:
- .erl
- .es
- .escript
- .hrl
@@ -848,6 +885,7 @@ GLSL:
- .frag
- .frg
- .fshader
- .geo
- .geom
- .glslv
- .gshader
@@ -860,6 +898,9 @@ Genshi:
extensions:
- .kid
tm_scope: text.xml.genshi
aliases:
- xml+genshi
- xml+kid
Gentoo Ebuild:
group: Shell
@@ -910,6 +951,13 @@ Go:
extensions:
- .go
Golo:
type: programming
color: "#f6a51f"
lexer: Golo
extensions:
- .golo
Gosu:
type: programming
color: "#82937f"
@@ -955,6 +1003,8 @@ Groff:
- '.6'
- '.7'
tm_scope: text.groff
aliases:
- nroff
Groovy:
type: programming
@@ -962,7 +1012,6 @@ Groovy:
color: "#e69f56"
extensions:
- .groovy
- .gradle
- .grt
- .gtpl
- .gvy
@@ -974,6 +1023,7 @@ Groovy Server Pages:
lexer: Java Server Page
aliases:
- gsp
- java server page
extensions:
- .gsp
tm_scope: text.html.jsp
@@ -998,6 +1048,10 @@ HTML+Django:
extensions:
- .mustache
- .jinja
aliases:
- html+django/jinja
- html+jinja
- htmldjango
HTML+ERB:
type: markup
@@ -1022,6 +1076,14 @@ HTTP:
extensions:
- .http
Hack:
type: programming
lexer: PHP
ace_mode: php
extensions:
- .hh
- .php
Haml:
group: HTML
type: markup
@@ -1069,6 +1131,8 @@ Hy:
color: "#7891b1"
extensions:
- .hy
aliases:
- hylang
IDL:
type: programming
@@ -1083,14 +1147,20 @@ IGOR Pro:
lexer: Igor
extensions:
- .ipf
aliases:
- igor
- igorpro
INI:
type: data
extensions:
- .ini
- .cfg
- .prefs
- .properties
tm_scope: source.ini
aliases:
- dosini
Inno Setup:
extensions:
@@ -1112,6 +1182,9 @@ Inform 7:
- .ni
- .i7x
tm_scope: source.inform
aliases:
- i7
- inform7
Inno Setup:
extensions:
@@ -1123,6 +1196,7 @@ IRC log:
search_term: irc
aliases:
- irc
- irc logs
extensions:
- .irclog
- .weechatlog
@@ -1323,9 +1397,12 @@ Lasso:
extensions:
- .lasso
- .las
- .lasso8
- .lasso9
- .ldml
tm_scope: file.lasso
aliases:
- lassoscript
Latte:
type: markup
@@ -1380,6 +1457,7 @@ Literate Haskell:
group: Haskell
search_term: lhs
aliases:
- lhaskell
- lhs
extensions:
- .lhs
@@ -1390,6 +1468,7 @@ LiveScript:
ace_mode: ls
color: "#499886"
aliases:
- live-script
- ls
extensions:
- .ls
@@ -1401,6 +1480,8 @@ Logos:
type: programming
extensions:
- .xm
- .x
- .xi
Logtalk:
type: programming
@@ -1427,6 +1508,7 @@ Lua:
- .nse
- .pd_lua
- .rbxs
- .wlua
interpreters:
- lua
@@ -1450,7 +1532,9 @@ MTML:
Makefile:
aliases:
- bsdmake
- make
- mf
extensions:
- .mak
- .mk
@@ -1483,7 +1567,7 @@ Markdown:
Mask:
type: markup
lexer: SCSS
lexer: Mask
color: "#f97732"
ace_mode: scss
extensions:
@@ -1494,9 +1578,14 @@ Mathematica:
type: programming
extensions:
- .mathematica
- .cdf
- .m
- .ma
- .nb
- .nbp
lexer: Mathematica
aliases:
- mma
Matlab:
type: programming
@@ -1571,6 +1660,8 @@ MoonScript:
type: programming
extensions:
- .moon
interpreters:
- moon
Myghty:
extensions:
@@ -1601,6 +1692,8 @@ Nginx:
extensions:
- .nginxconf
tm_scope: source.nginx
aliases:
- nginx configuration file
Nimrod:
type: programming
@@ -1621,6 +1714,8 @@ Nix:
lexer: Nix
extensions:
- .nix
aliases:
- nixos
Nu:
type: programming
@@ -1668,6 +1763,7 @@ Objective-C:
aliases:
- obj-c
- objc
- objectivec
extensions:
- .m
- .h
@@ -1679,6 +1775,7 @@ Objective-C++:
aliases:
- obj-c++
- objc++
- objectivec++
extensions:
- .mm
@@ -1687,6 +1784,8 @@ Objective-J:
color: "#ff0c5a"
aliases:
- obj-j
- objectivej
- objj
extensions:
- .j
- .sj
@@ -1786,6 +1885,8 @@ PHP:
- Phakefile
interpreters:
- php
aliases:
- inc
Pan:
type: programming
@@ -1794,6 +1895,13 @@ Pan:
extensions:
- .pan
Papyrus:
type: programming
color: "#6600cc"
lexer: Text only
extensions:
- .psc
Parrot:
type: programming
color: "#f3ca0a"
@@ -1898,6 +2006,8 @@ PostScript:
- .ps
- .eps
tm_scope: source.postscript
aliases:
- postscr
PowerShell:
type: programming
@@ -1979,6 +2089,7 @@ Python:
- .pyp
- .pyt
- .pyw
- .tac
- .wsgi
- .xpy
filenames:
@@ -1995,6 +2106,7 @@ Python traceback:
searchable: false
extensions:
- .pytb
tm_scope: text.python.traceback
QML:
type: markup
@@ -2016,6 +2128,7 @@ R:
aliases:
- R
- Rscript
- splus
extensions:
- .r
- .R
@@ -2054,6 +2167,8 @@ RHTML:
extensions:
- .rhtml
tm_scope: text.html.ruby
aliases:
- html+ruby
RMarkdown:
type: prose
@@ -2081,6 +2196,9 @@ Ragel in Ruby Host:
color: "#ff9c2e"
extensions:
- .rl
aliases:
- ragel-rb
- ragel-ruby
Raw token data:
search_term: raw
@@ -2107,6 +2225,8 @@ Red:
extensions:
- .red
- .reds
aliases:
- red/system
Redcode:
extensions:
@@ -2288,7 +2408,7 @@ Shell:
type: programming
lexer: Bash
search_term: bash
color: "#5861ce"
color: "#89e051"
aliases:
- sh
- bash
@@ -2300,6 +2420,7 @@ Shell:
- .cgi
- .command
- .fcgi
- .ksh
- .tmux
- .zsh
interpreters:
@@ -2314,6 +2435,10 @@ ShellSession:
lexer: Bash Session
extensions:
- .sh-session
aliases:
- bash session
- console
tm_scope: text.shell-session
Shen:
type: programming
@@ -2342,6 +2467,8 @@ Smalltalk:
color: "#596706"
extensions:
- .st
aliases:
- squeak
Smarty:
extensions:
@@ -2400,6 +2527,7 @@ SuperCollider:
lexer: Text only
extensions:
- .scd
- .sc
Swift:
type: programming
@@ -2595,6 +2723,9 @@ Visual Basic:
- .vbhtml
- .vbs
tm_scope: source.vbnet
aliases:
- vb.net
- vbnet
Volt:
type: programming
@@ -2665,6 +2796,7 @@ XML:
- .vcxproj
- .vxml
- .wsdl
- .wsf
- .wxi
- .wxl
- .wxs
@@ -2680,6 +2812,7 @@ XML:
filenames:
- .classpath
- .project
- build.xml.dist
- phpunit.xml.dist
XProc:

View File

@@ -1,5 +1,5 @@
begin
require 'json'
require 'yajl'
rescue LoadError
require 'yaml'
end
@@ -19,7 +19,7 @@ module Linguist
# Hash of serialized samples object
def self.cache
@cache ||= begin
serializer = defined?(JSON) ? JSON : YAML
serializer = defined?(Yajl) ? Yajl : YAML
serializer.load(File.read(PATH))
end
end

View File

@@ -36,15 +36,16 @@
# Go dependencies
- Godeps/_workspace/
# Bootstrap minified css and js
- (^|/)bootstrap([^.]*)(\.min)?\.(js|css)$
# Minified JavaScript and CSS
- (\.|-)min\.(js|css)$
# Bootstrap css and js
- (^|/)bootstrap([^.]*)\.(js|css)$
# Font Awesome
- font-awesome.min.css
- font-awesome.css
# Foundation css
- foundation.min.css
- foundation.css
# Normalize.css
@@ -56,7 +57,6 @@
# Animate.css
- animate.css
- animate.min.css
# Vendored dependencies
- third[-_]?party/
@@ -73,12 +73,12 @@
## Commonly Bundled JavaScript frameworks ##
# jQuery
- (^|/)jquery([^.]*)(\.min)?\.js$
- (^|/)jquery\-\d\.\d+(\.\d+)?(\.min)?\.js$
- (^|/)jquery([^.]*)\.js$
- (^|/)jquery\-\d\.\d+(\.\d+)?\.js$
# jQuery UI
- (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?(\.min)?\.(js|css)$
- (^|/)jquery\.(ui|effects)\.([^.]*)(\.min)?\.(js|css)$
- (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?\.(js|css)$
- (^|/)jquery\.(ui|effects)\.([^.]*)\.(js|css)$
# Prototype
- (^|/)prototype(.*)\.js$
@@ -116,21 +116,20 @@
- (^|/)shLegacy\.js$
# AngularJS
- (^|/)angular([^.]*)(\.min)?\.js$
- (^|/)angular([^.]*)\.js$
# D3.js
- (^|\/)d3(\.v\d+)?([^.]*)(\.min)?\.js$
- (^|\/)d3(\.v\d+)?([^.]*)\.js$
# React
- (^|/)react(-[^.]*)?(\.min)?\.js$
- (^|/)react(-[^.]*)?\.js$
# Modernizr
- (^|/)modernizr\-\d\.\d+(\.\d+)?(\.min)?\.js$
- (^|/)modernizr\-\d\.\d+(\.\d+)?\.js$
- (^|/)modernizr\.custom\.\d+\.js$
# Knockout
- (^|/)knockout-(\d+\.){3}(debug\.)?js$
- knockout-min.js
## Python ##
@@ -168,8 +167,8 @@
- \.intellisense\.js$
# jQuery validation plugin (MS bundles this with asp.net mvc)
- (^|/)jquery([^.]*)\.validate(\.unobtrusive)?(\.min)?\.js$
- (^|/)jquery([^.]*)\.unobtrusive\-ajax(\.min)?\.js$
- (^|/)jquery([^.]*)\.validate(\.unobtrusive)?\.js$
- (^|/)jquery([^.]*)\.unobtrusive\-ajax\.js$
# Microsoft Ajax
- (^|/)[Mm]icrosoft([Mm]vc)?([Aa]jax|[Vv]alidation)(\.debug)?\.js$
@@ -196,7 +195,7 @@
- (^|/)extjs/welcome/
# Html5shiv
- (^|/)html5shiv(\.min)?\.js$
- (^|/)html5shiv\.js$
# Samples folders
- ^[Ss]amples/
@@ -215,8 +214,8 @@
- ^[Tt]est/fixtures/
# PhoneGap/Cordova
- (^|/)cordova([^.]*)(\.min)?\.js$
- (^|/)cordova\-\d\.\d(\.\d)?(\.min)?\.js$
- (^|/)cordova([^.]*)\.js$
- (^|/)cordova\-\d\.\d(\.\d)?\.js$
# Foundation js
- foundation(\..*)?\.js$
@@ -236,7 +235,6 @@
# Octicons
- octicons.css
- octicons.min.css
- sprockets-octicons.scss
# Typesafe Activator

View File

@@ -1,3 +1,3 @@
module Linguist
VERSION = "3.4.1"
VERSION = "3.5.1"
end

10
samples/C++/bar.hh Normal file
View File

@@ -0,0 +1,10 @@
class Bar
{
protected:
char *name;
public:
void hello();
}

67
samples/Golo/adapters.golo Executable file
View File

@@ -0,0 +1,67 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Adapters
local function list_sample = |fabric| {
println(">>> list_sample()")
let carbonCopy = list[]
let conf = map[
["extends", "java.util.ArrayList"],
["overrides", map[
["*", |super, name, args| {
if name == "add" {
if args: length() == 2 {
carbonCopy: add(args: get(1))
} else {
carbonCopy: add(args: get(1), args: get(2))
}
}
return super: invokeWithArguments(args)
}
]]
]]
let list = fabric: maker(conf): newInstance()
list: add("bar")
list: add(0, "foo")
list: add("baz")
println(" list: " + list + " " + list: getClass())
println("carbonCopy: " + carbonCopy + " " + carbonCopy: getClass())
}
local function runnable_sample = |fabric| {
println(">>> runnable_sample")
let result = array[1, 2, 3]
let conf = map[
["interfaces", ["java.io.Serializable", "java.lang.Runnable"]],
["implements", map[
["run", |this| {
for (var i = 0, i < result: length(), i = i + 1) {
result: set(i, result: get(i) + 10)
}
}]
]]
]
let runner = fabric: maker(conf): newInstance()
runner: run()
println(" result: " + result: toString())
println("serializable? " + (runner oftype java.io.Serializable.class))
println(" runnable? " + (runner oftype java.lang.Runnable.class))
}
function main = |args| {
let fabric = AdapterFabric()
list_sample(fabric)
runnable_sample(fabric)
}

84
samples/Golo/async.golo Executable file
View File

@@ -0,0 +1,84 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.AsyncHelpers
import gololang.Async
import java.util.concurrent.TimeUnit
import java.util.concurrent.Executors
local function fib = |n| {
if n <= 1 {
return n
} else {
return fib(n - 1) + fib(n - 2)
}
}
function main = |args| {
let executor = newCachedThreadPool()
println("Let's do some useless asynchronous operations...")
var f = executor: enqueue({
Thread.sleep(1000_L)
return 666
})
f:
onSet(|v| -> println(">>> #slow -> " + v)):
onFail(|e| -> println(">>> #fail -> " + e))
f:
cancel(true)
f = executor: enqueue({
Thread.sleep(1000_L)
return 666
})
f:
onSet(|v| -> println(">>> #ok -> " + v)):
onFail(|e| -> println(">>> #wtf? -> " + e))
let fib_10 = promise()
let fib_20 = promise()
let fib_30 = promise()
let fib_40 = promise()
let futures = [
fib_10: future(), fib_20: future(),
fib_30: future(), fib_40: future()
]
executor: submit(-> fib_10: set(fib(10)))
executor: submit(-> fib_20: set(fib(20)))
executor: submit(-> fib_30: set(fib(30)))
executor: submit(-> fib_40: set(fib(40)))
all(futures): onSet(|results| -> println(">>> Fibs: " + results))
let truth = promise()
truth:
future():
map(|v| -> "truth=" + v):
onSet(|v| -> executor: submit(-> println(">>> (another thread) " + v))):
onSet(|v| -> println(">>> (same thread) " + v))
executor: submit({
Thread.sleep(500_L)
truth: set(42)
})
Thread.sleep(1000_L)
executor: shutdown()
executor: awaitTermination(2_L, SECONDS())
println("Bye!")
}

37
samples/Golo/augmentations.golo Executable file
View File

@@ -0,0 +1,37 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Augmentations
import java.util.LinkedList
augment java.util.List {
function with = |this, value| {
this: add(value)
return this
}
}
augment java.util.Collection {
function doToEach = |this, func| {
foreach (element in this) {
func(element)
}
}
}
function main = |args| {
let list = LinkedList(): with("foo"): with("bar"): with("baz")
list: doToEach(|value| -> println(">>> " + value))
}

43
samples/Golo/closures.golo Executable file
View File

@@ -0,0 +1,43 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Closures
local function sayHello = |who| -> "Hello " + who + "!"
function main = |args| {
let adder = |a, b| -> a + b
println(adder: invokeWithArguments(1, 2))
println(adder(1, 2))
let addToTen = adder: bindTo(10)
println(addToTen: invokeWithArguments(2))
println(addToTen(2))
let adding = |x| -> |y| -> adder(x, y)
let addingTen = adding(10)
println(addingTen(4))
println(adding(2)(4))
println(sayHello("Julien"))
let list = java.util.LinkedList()
let pump_it = {
list: add("I heard you say")
list: add("Hey!")
list: add("Hey!")
}
pump_it()
println(list)
}

34
samples/Golo/coin-change.golo Executable file
View File

@@ -0,0 +1,34 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module CoinChange
import java.util.LinkedList
function change = |money, coins| -> match {
when money == 0 then 1
when (money < 0) or (coins: isEmpty()) then 0
otherwise change(money - coins: head(), coins) + change(money, coins: tail())
}
function main = |args| {
let coins = LinkedList(): append(1, 2, 5, 10, 20)
println("Coins: " + coins)
println("0: " + change(0, coins))
println("1: " + change(1, coins))
println("2: " + change(2, coins))
println("10: " + change(10, coins))
println("12: " + change(12, coins))
println("6: " + change(6, coins))
}

View File

@@ -0,0 +1,55 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.CollectionLiterals
local function play_with_tuples = {
let hello = ["Hello", "world", "!"]
foreach str in hello {
print(str + " ")
}
println("")
println(hello: get(0) + "-" + hello: get(1) + "-" + hello: get(2))
println(hello: join("/"))
}
local function play_with_literals = {
let data = [
[1, 2, 3],
tuple[1, 2, 3],
array[1, 2, 3],
set[1, 2, 3, 3, 1],
map[
["a", 10],
["b", 20]
],
vector[1, 2, 3],
list[1, 2, 3]
]
data: each(|element| {
println(element: toString())
println(" type: " + element: getClass())
})
}
function main = |args| {
println(">>> Literals")
play_with_literals()
println("\n>>> Tuples")
play_with_tuples()
}

View File

@@ -0,0 +1,53 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.ContextDecorator
import gololang.Decorators
let myContext = defaultContext():
count(0):
define("entry", |this, args| {
this: count(this: count() + 1)
println("hello:" + this: count())
return args
}):
define("exit", |this, result| {
require(result >= 3, "wrong value")
println("goobye")
return result
}):
define("catcher", |this, e| {
println("Caught " + e)
throw e
}):
define("finallizer", |this| {println("do some cleanup")})
@withContext(myContext)
function foo = |a, b| {
println("Hard computation")
return a + b
}
function main = |args| {
println(foo(1,2))
println("====")
println(withContext(myContext)(|a| -> 2*a)(3))
println("====")
try {
println(foo(1, 1))
} catch (e) { }
}

83
samples/Golo/decorators.golo Executable file
View File

@@ -0,0 +1,83 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Decorators
import java.util.LinkedList
function simple_decorator = |func| {
return |a,b| -> func(a+1,b+1)
}
@simple_decorator
function simple_adder = |x,y| -> x + y
function decorator_with_params = |param1, param2|{
return |func| {
return |a,b| -> func(a+param1,b+param2)
}
}
@decorator_with_params(10,2)
function parametrized_adder = |x,y| -> x + y
function generic_decorator = |func| {
return |args...| {
println("number of params : "+args: length())
return func: invokeWithArguments(args)
}
}
@generic_decorator
function generic_adder0 = -> 42
@generic_decorator
function generic_adder1 = |x| -> x
@generic_decorator
function generic_adder2 = |x,y| -> x + y
@generic_decorator
function generic_adder3 = |x,y,z| -> x + y + z
function list_sum_decorator = |func| {
return |this| -> func(this) - 8
}
augment java.util.List {
@list_sum_decorator
function sum = |this| {
var acc = 0
foreach elem in this {
acc = acc + elem
}
return acc
}
}
function main = |args| {
println(simple_adder(10,30))
println(parametrized_adder(10,20))
println(generic_adder0())
println(generic_adder1(42))
println(generic_adder2(20,22))
println(generic_adder3(10,12,20))
let list = LinkedList()
list: add(5)
list: add(10)
list: add(15)
list: add(20)
println(list: sum())
}

View File

@@ -0,0 +1,88 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.DynamicEvaluation
import gololang.EvaluationEnvironment
local function test_asModule = |env| {
let code =
"""
module foo
function a = -> "a!"
function b = -> "b!"
"""
let mod = env: asModule(code)
let a = fun("a", mod)
let b = fun("b", mod)
println(">>> asModule()")
println(a())
println(b())
}
local function test_anonymousModule = |env| {
let code =
"""
function a = -> "a."
function b = -> "b."
"""
let mod = env: anonymousModule(code)
let a = fun("a", mod)
let b = fun("b", mod)
println(">>> anonymousModule()")
println(a())
println(b())
}
local function test_asFunction = |env| {
let code = "return (a + b) * 2"
let f = env: asFunction(code, "a", "b")
println(">>> asFunction")
println(f(10, 20))
}
local function test_def = |env| {
let code = "|a, b| -> (a + b) * 2"
let f = env: def(code)
println(">>> def")
println(f(10, 20))
}
local function test_run = |env| {
let code = """println(">>> run")
foreach (i in range(0, 3)) {
println("w00t")
}"""
env: run(code)
}
local function test_run_map = |env| {
let code = """println(">>> run_map")
println(a)
println(b)
"""
let values = java.util.TreeMap(): add("a", 1): add("b", 2)
env: run(code, values)
}
function main = |args| {
let env = EvaluationEnvironment()
test_asModule(env)
test_anonymousModule(env)
test_asFunction(env)
test_def(env)
test_run(env)
test_run_map(env)
}

View File

@@ -0,0 +1,29 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.DynamicObjectPerson
local function mrbean = -> DynamicObject():
name("Mr Bean"):
email("mrbean@gmail.com"):
define("toString", |this| -> this: name() + " <" + this: email() + ">")
function main = |args| {
let bean = mrbean()
println(bean: toString())
bean: email("mrbean@outlook.com")
println(bean: toString())
}

34
samples/Golo/echo-args.golo Executable file
View File

@@ -0,0 +1,34 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module EchoArgs
function main = |args| {
println("With a for loop and an index:")
for (var i = 0, i < args: length(), i = i + 1) {
println(" #" + i + " -> " + args: get(i))
}
println("With a foreach loop:")
foreach arg in args {
println(" " + arg)
}
println("With a foreach over a range:")
foreach i in range(0, args: length()) {
println(" #" + i + " -> " + args: get(i))
}
}

View File

@@ -0,0 +1,31 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module sample.EnumsThreadState
import java.lang.Thread$State
function main = |args| {
# Call the enum entry like a function
let new = Thread$State.NEW()
println("name=" + new: name() + ", ordinal=" + new: ordinal())
println("-----------")
# Walk through all enum entries
foreach element in Thread$State.values() {
println("name=" + element: name() + ", ordinal=" + element: ordinal())
}
}

39
samples/Golo/fibonacci.golo Executable file
View File

@@ -0,0 +1,39 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Fibonacci
import java.lang.System
function fib = |n| {
if n <= 1 {
return n
} else {
return fib(n - 1) + fib(n - 2)
}
}
local function run = {
let start = System.currentTimeMillis()
let result = fib(40)
let duration = System.currentTimeMillis() - start
println(">>> " + result + " (took " + duration + "ms)")
}
function main = |args| {
while true {
run()
}
}

20
samples/Golo/helloworld.golo Executable file
View File

@@ -0,0 +1,20 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module hello.World
function main = |args| {
println("Hello world!")
}

53
samples/Golo/http-server.golo Executable file
View File

@@ -0,0 +1,53 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.WebServer
import java.lang
import java.net.InetSocketAddress
import com.sun.net.httpserver
import com.sun.net.httpserver.HttpServer
function main = |args| {
let server = HttpServer.create(InetSocketAddress("localhost", 8081), 0)
server: createContext("/", |exchange| {
let headers = exchange: getResponseHeaders()
let response = StringBuilder():
append("Requested URI: "):
append(exchange: getRequestURI()):
append("\n"):
append("Current time: "):
append(java.util.Date()):
append("\n"):
toString()
headers: set("Content-Type", "text/plain")
exchange: sendResponseHeaders(200, response: length())
exchange: getResponseBody(): write(response: getBytes())
exchange: close()
})
server: createContext("/shutdown", |exchange| {
let response = "Ok, thanks, bye!"
exchange: getResponseHeaders(): set("Content-Type", "text/plain")
exchange: sendResponseHeaders(200, response: length())
exchange: getResponseBody(): write(response: getBytes())
exchange: close()
server: stop(5)
})
server: start()
println(">>> http://localhost:8081/")
}

65
samples/Golo/logdeco.golo Executable file
View File

@@ -0,0 +1,65 @@
module samples.LogDeco
function log1 = |msg| {
return |fun| {
return |args...| {
println(msg)
return fun: invokeWithArguments(args)
}
}
}
@log1("calling foo")
function foo = |a| {
println("foo got a " + a)
}
@log1("I'am a bar")
function bar = |a| -> 2*a
let sayHello = log1("Hello")
@sayHello
function baz = -> "Goodbye"
function log2 = |msgBefore| -> |msgAfter| -> |func| -> |args...| {
println(msgBefore)
let res = func: invokeWithArguments(args)
println(msgAfter)
return res
}
@log2("enter foo")("exit foo")
function spam = |a| {
println("foo: " + a)
}
function logEnterExit = |name| -> log2("# enter " + name)("# exit " + name)
@logEnterExit("bar")
function egg = { println("doing something...") }
function main = |args| {
foo("bar")
println("---")
println(bar(21))
println("---")
println(baz())
println("---")
spam("bar")
println("---")
egg()
println("---")
let strange_use = log2("hello")("goodbye")({println(":p")})
strange_use()
println("---")
log2("another")("use")(|a|{println(a)})("strange")
}

View File

@@ -0,0 +1,40 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Matching
import java.util.LinkedList
local function data = {
let list = LinkedList()
list: add("foo@bar.com")
list: add("+33.6.11.22.33")
list: add("http://golo-lang.org/")
list: add("def foo = bar(_._) with :> T")
return list
}
local function what_it_could_be = |item| -> match {
when item: contains("@") then "an email?"
when item: startsWith("+33") then "a French phone number?"
when item: startsWith("http://") then "a website URL?"
otherwise "I have no clue, mate!"
}
function main = |args| {
foreach item in data() {
println(item + " => " + what_it_could_be(item))
}
}

24
samples/Golo/max-int.golo Executable file
View File

@@ -0,0 +1,24 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.MaxInt
local function max_int = {
return java.lang.Integer.MAX_VALUE()
}
function main = |args| {
println(max_int())
}

55
samples/Golo/memoize.golo Executable file
View File

@@ -0,0 +1,55 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.MemoizeDecorator
import gololang.Decorators
import java.lang.System
let memo = memoizer()
@memo
function fib = |n| {
if n <= 1 {
return n
} else {
return fib(n - 1) + fib(n - 2)
}
}
@memo
function foo = |n| -> n
local function run = {
let start = System.currentTimeMillis()
let result = fib(40)
let duration = System.currentTimeMillis() - start
println(">>> fib(40) = " + result + " (took " + duration + "ms)")
}
local function run2 = {
let start = System.currentTimeMillis()
let result = foo(40)
let duration = System.currentTimeMillis() - start
println(">>> foo(40) = " + result + " (took " + duration + "ms)")
}
function main = |args| {
foreach i in range(0, 5) {
println("run " + i)
run()
run2()
}
}

43
samples/Golo/null-safety.golo Executable file
View File

@@ -0,0 +1,43 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module DealingWithNull
import java.util
function main = |args| {
# Data model
let contacts = map[
["mrbean", map[
["email", "bean@gmail.com"],
["url", "http://mrbean.com"]
]],
["larry", map[
["email", "larry@iamricherthanyou.com"]
]]
]
# MrBean and Larry
let mrbean = contacts: get("mrbean")
let larry = contacts: get("larry")
# Illustrates orIfNull
println(mrbean: get("url") orIfNull "n/a")
println(larry: get("url") orIfNull "n/a")
# Querying a non-existent data model because there is no 'address' entry
println(mrbean: get("address")?: street()?: number() orIfNull "n/a")
}

View File

@@ -0,0 +1,65 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.PrepostDecorator
import gololang.Decorators
let isInteger = isOfType(Integer.class)
@checkResult(isString(): andThen(lengthIs(2)))
@checkArguments(isInteger: andThen(isPositive()), isString())
function foo = |a, b| {
return b + a
}
let myCheck = checkArguments(isInteger: andThen(isPositive()))
@myCheck
function inv = |v| -> 1.0 / v
let isPositiveInt = isInteger: andThen(isPositive())
@checkArguments(isPositiveInt)
function mul = |v| -> 10 * v
@checkArguments(isNumber())
function num = |v| -> "ok"
@checkArguments(isNotNull())
function notnull = |v| -> "ok"
function main = |args| {
try { println(foo(1, "b")) } catch (e) { println(e) }
try { println(foo(-1, "b")) } catch (e) { println(e) }
try { println(foo("a", 2)) } catch (e) { println(e) }
try { println(foo(1, 2)) } catch (e) { println(e) }
try { println(foo(10, "ab")) } catch (e) { println(e) }
try { println(inv(10)) } catch (e) { println(e) }
try { println(inv(0)) } catch (e) { println(e) }
try { println(mul(5)) } catch (e) { println(e) }
try { println(mul(0)) } catch (e) { println(e) }
try { println(num(1)) } catch (e) { println(e) }
try { println(num(1_L)) } catch (e) { println(e) }
try { println(num(1.5)) } catch (e) { println(e) }
try { println(num(1.5_F)) } catch (e) { println(e) }
try { println(num("a")) } catch (e) { println(e) }
try { println(num('a')) } catch (e) { println(e) }
try { println(notnull('1')) } catch (e) { println(e) }
try { println(notnull(null)) } catch (e) { println(e) }
}

69
samples/Golo/structs.golo Executable file
View File

@@ -0,0 +1,69 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module StructDemo
struct Point = { x, y }
augment StructDemo.types.Point {
function move = |this, offsetX, offsetY| {
this: x(this: x() + offsetX)
this: y(this: y() + offsetY)
return this
}
function relative = |this, offsetX, offsetY| -> Point(this: x() + offsetX, this: y() + offsetY)
}
function main = |args| {
let p1 = Point(1, 2)
let p2 = Point(): x(1): y(2)
let p3 = p1: frozenCopy()
let p4 = p1: frozenCopy()
println(p1)
println("x = " + p1: x())
println("y = " + p1: y())
println("p1 == p2 " + (p1 == p2))
println("p1 == p3 " + (p1 == p3))
println("p3 == p4 " + (p3 == p4))
println("#p1 " + p1: hashCode())
println("#p2 " + p2: hashCode())
println("#p3 " + p3: hashCode())
println("#p4 " + p4: hashCode())
println("p1: members() " + p1: members())
println("p1: values() " + p1: values())
foreach item in p1 {
println(item: get(0) + " -> " + item: get(1))
}
println("p1: set(\"x\", 10) " + p1: set("x", 10))
println("p1: move(10, 5) " + p1: move(10, 5))
println("p1: relative(11, 6) " + p1: relative(11, 6))
let p5 = ImmutablePoint(10, 20)
println("p5: " + p5)
try {
p5: x(100)
} catch (expected) {
println("p5 is immutable, so... " + expected: getMessage())
}
}

View File

@@ -0,0 +1,43 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.SwingActionListener
import java.awt.event
import javax.swing
import javax.swing.WindowConstants
local function listener = |handler| -> asInterfaceInstance(ActionListener.class, handler)
function main = |args| {
let frame = JFrame("Action listeners")
frame: setDefaultCloseOperation(EXIT_ON_CLOSE())
let button = JButton("Click me!")
button: setFont(button: getFont(): deriveFont(96.0_F))
# Using a helper function
button: addActionListener(listener(|event| -> println("Clicked!")))
# Using a standard augmentation: MethodHandle::to(Class)
button: addActionListener((|event| -> println("[click]")): to(ActionListener.class))
# Straight closure passing
button: addActionListener(|event| -> println("( )"))
frame: getContentPane(): add(button)
frame: pack()
frame: setVisible(true)
}

View File

@@ -0,0 +1,31 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.SwingHelloWorld
import javax.swing
import javax.swing.WindowConstants
function main = |args| {
let frame = JFrame("Hello world")
frame: setDefaultCloseOperation(EXIT_ON_CLOSE())
let label = JLabel("Hello world")
label: setFont(label: getFont(): deriveFont(128.0_F))
frame: getContentPane(): add(label)
frame: pack()
frame: setVisible(true)
}

View File

@@ -0,0 +1,90 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.TemplatesChatWebapp
import java.lang
import java.io
import java.net.InetSocketAddress
import com.sun.net.httpserver
import com.sun.net.httpserver.HttpServer
local function redirect = |exchange, to| {
exchange: getResponseHeaders(): set("Location", to)
exchange: sendResponseHeaders(303, 0)
exchange: close()
}
local function respond = |exchange, body| {
exchange: getResponseHeaders(): set("Content-Type", "text/html")
exchange: sendResponseHeaders(200, body: length())
exchange: getResponseBody(): write(body: getBytes())
exchange: close()
}
# This is leaky and works with just 1 POST parameter...
local function extract_post = |exchange, posts| {
let reader = BufferedReader(InputStreamReader(exchange: getRequestBody()))
var line = reader: readLine()
while line isnt null {
if line: startsWith("msg=") {
posts: add(java.net.URLDecoder.decode(line: substring(4), "UTF-8"))
}
line = reader: readLine()
}
reader: close()
}
local function index = |posts, template, exchange| {
if exchange: getRequestMethod() == "POST" {
extract_post(exchange, posts)
redirect(exchange, "/")
} else {
respond(exchange, template(posts))
}
}
local function index_template = -> """
<%@params posts %>
<!DOCTYPE html>
<html>
<head>
<title>Golo Chat</title>
</head>
<body>
<form action="/" method="post">
<input type="text" name="msg">
<input type="submit" value="Send">
</form>
<div>
<h3>Last posts</h3>
<% foreach post in posts { %>
<div>
<%= post %>
</div>
<% } %>
</div>
</body>
</html>
"""
function main = |args| {
let index_tpl = gololang.TemplateEngine(): compile(index_template())
let posts = java.util.concurrent.ConcurrentLinkedDeque()
let server = HttpServer.create(InetSocketAddress("localhost", 8081), 0)
server: createContext("/", ^index: bindTo(posts): bindTo(index_tpl))
server: start()
println(">>> http://localhost:8081/")
}

View File

@@ -0,0 +1,51 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module MoreCoolContainers
function main = |args| {
println(">>> DynamicVariable")
let dyn = DynamicVariable("Foo")
println(dyn: value())
let t1 = Thread({
dyn: withValue(666, {
println(dyn: value())
})
})
let t2 = Thread({
dyn: withValue(69, {
println(dyn: value())
})
})
t1: start()
t2: start()
t1: join()
t2: join()
println(dyn: value())
println(">>> Observable")
let foo = Observable("Foo")
foo: onChange(|v| -> println("foo = " + v))
let mapped = foo: map(|v| -> v + "!")
mapped: onChange(|v| -> println("mapped = " + v))
foo: set("69")
}

48
samples/Golo/workers.golo Executable file
View File

@@ -0,0 +1,48 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Workers
import java.lang.Thread
import java.util.concurrent
import gololang.concurrent.workers.WorkerEnvironment
local function pusher = |queue, message| -> queue: offer(message)
local function generator = |port, message| {
foreach i in range(0, 100) {
port: send(message)
}
}
function main = |args| {
let env = WorkerEnvironment.builder(): withFixedThreadPool()
let queue = ConcurrentLinkedQueue()
let pusherPort = env: spawn(^pusher: bindTo(queue))
let generatorPort = env: spawn(^generator: bindTo(pusherPort))
let finishPort = env: spawn(|any| -> env: shutdown())
foreach i in range(0, 10) {
generatorPort: send("[" + i + "]")
}
Thread.sleep(2000_L)
finishPort: send("Die!")
env: awaitTermination(2000)
println(queue: reduce("", |acc, next| -> acc + " " + next))
}

55
samples/Hack/Assert.hh Normal file
View File

@@ -0,0 +1,55 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class AssertException extends Exception {}
final class Assert {
public static function isNum(mixed $x): num {
if (is_float($x)) {
return $x;
} else if (is_int($x)) {
return $x;
}
throw new AssertException('Expected an int or float value');
}
public static function isInt(mixed $x): int {
if (is_int($x)) {
return $x;
}
throw new AssertException('Expected an int');
}
public static function isFloat(mixed $x): float {
if (is_float($x)) {
return $x;
}
throw new AssertException('Expected a float');
}
public static function isString(mixed $x): string {
if (is_string($x)) {
return $x;
}
throw new AssertException('Expected a string');
}
// For arrays you need to check every element
public static function isArrayOf<T>(
(function(mixed): T) $fn,
mixed $x,
): array<T> {
if (is_array($x)) {
return array_map($fn, $x);
}
throw new AssertException('Expected an array');
}
}

View File

@@ -0,0 +1,52 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class AssertRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'Assert';
}
<<Override>>
protected function getDescription(): ?string {
return 'When you have values with unknown types, it is useful to make '.
'some runtime assertions and have the type checker understand. This '.
'recipe demonstrates one approach.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'Assert.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector{
tuple ('Mixed Types', 'hack.annotations.mixedtypes'),
tuple ('Type Inference', 'hack.otherrulesandfeatures.typeinference'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return assert_main();
}
public function getDemoXHP(): ?:xhp {
return null;
}
}

View File

@@ -0,0 +1,39 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/startup/init.php';
abstract class Controller {
protected function __construct() {
startup();
}
abstract protected function getCSS(): Set<string>;
abstract protected function getJS(): Set<string>;
abstract protected function getTitle(): string;
abstract protected function render(): :xhp;
final protected function getHead(): :xhp {
$css = $this->getCSS()->toVector()->map(
($css) ==> <link rel="stylesheet" type="text/css" href={$css} />
);
$js = $this->getJS()->toVector()->map(
($js) ==> <script src={$js} />
);
return
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>{$this->getTitle()}</title>
{$css->toArray()}
{$js->toArray()}
</head>;
}
}

View File

@@ -0,0 +1,52 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class DBResultRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'DB Result';
}
<<Override>>
protected function getDescription(): ?string {
return 'Fetching data from a DB introduces a few typing challenges. '.
'First, the data comes back untyped. Second, a row in a DB generally '.
'contains columns of different types.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'FakeDB.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector{
tuple ('Hack Shapes', 'hack.shapes'),
tuple ('Mixed Types', 'hack.annotations.mixedtypes'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return db_result_main();
}
public function getDemoXHP(): ?:xhp {
return null;
}
}

View File

@@ -0,0 +1,22 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
final class :documentation extends :x:element {
attribute string name;
protected function render(): :xhp {
$name = implode('.', explode(' ', $this->getAttribute('name'))).".php";
$href = "http://hhvm.com/manual/en/$name";
return <a class="docs button" href={$href} target="_blank">docs &rarr;</a>;
}
}

65
samples/Hack/FakeDB.hh Normal file
View File

@@ -0,0 +1,65 @@
<?hh // strict
type DBResultExtra = shape('age' => int);
type DBResult = shape(
'id' => int,
'name' => string,
'extra' => DBResultExtra,
);
final class FakeDB {
public function getRawRows(): array<array<string, mixed>> {
$good_extra = json_encode(array('age' => 40));
$bad_extra = 'corrupt data';
// Real code would query a DB, but for now let's hardcode it
return array(
array(
'id' => 123,
'name' => 'Alice',
'extra' => $good_extra,
),
array(
'id' => 456,
'name' => 'Bob',
'extra' => $bad_extra,
),
);
}
/**
* When processing untyped data you need to check each piece of data and
* figure out whether to give up or recover when the data is bad
*/
public function processRow(array<string, mixed> $row): ?DBResult {
$row = Map::fromArray($row);
$id = $row->contains('id') ? $row['id'] : null;
$name = $row->contains('name') ? $row['name'] : null;
$extra = $row->contains('extra') ? json_decode($row['extra'], true) : null;
// Ignore rows with invalid IDs or names
if (!is_int($id) || !is_string($name)) {
return null;
}
// Try to recover from a bad extra column
if (!is_array($extra)) {
$extra = shape('age' => 0);
} else {
$extra = Map::fromArray($extra);
$extra = shape('age' => $extra->contains('age') ? $extra['age'] : 0);
}
return shape('id' => $id, 'name' => $name, 'extra' => $extra);
}
public function getDBResults(): Vector<DBResult> {
$ret = Vector {};
foreach ($this->getRawRows() as $raw_row) {
$row = $this->processRow($raw_row);
if ($row !== null) {
$ret->add($row);
}
}
return $ret;
}
}

View File

@@ -0,0 +1,72 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class GetAndPostRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return '$_GET and $_POST';
}
<<Override>>
protected function getDescription(): ?string {
return 'A small example of how to interact with superglobals and the '.
'untyped data they can contain.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'NonStrictFile.php',
'StrictFile.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector {
tuple('invariant()', 'hack.otherrulesandfeatures.invariant'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return get_and_post_main();
}
public function getDemoXHP(): :xhp {
$url = '/recipes/get-and-post/';
return
<x:frag>
<div>
<a href={"$url?myIntParam=8675309#demo"} class="button">GET myIntParam=8675309</a>
</div>
<div>
<a href={"$url?myIntParam=boom#demo"} class="button">GET myIntParam=boom</a>
</div>
<div>
<form action={"$url#demo"} method="post">
<input type="hidden" name="myIntParam" value="5551234"/>
<input type="submit" class="button" value="POST myIntParam=5551234"/>
</form>
</div>
<div>
<form action={"$url#demo"} method="post">
<input type="hidden" name="myIntParam" value="boom"/>
<input type="submit" class="button" value="POST myIntParam=boom"/>
</form>
</div>
</x:frag>;
}
}

View File

@@ -0,0 +1,30 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
abstract class GetController extends Controller {
final protected function __construct(private Request $request) {
parent::__construct();
}
final protected function getRequest(): Request {
return $this->request;
}
final public function go(array<mixed, mixed> $get): void {
$request = new Request(Map::fromArray($get));
$controller = new static($request);
echo "<!DOCTYPE html>";
$head = $controller->getHead();
$body = $controller->render();
echo (string)$head;
echo (string)$body;
}
}

View File

@@ -0,0 +1,38 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/standard-page/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
class HomeController extends GetController {
use StandardPage;
protected function getTitle(): string {
return 'Hack Cookbook';
}
protected function renderMainColumn(): :xhp {
return <div>
<h1>Cookbook</h1>
<p>
The Hack Cookbook helps you write Hack code by giving you examples of
Hack code. It is written in Hack and is open source. If you
<a href="http://github.com/facebook/hack-example-site">
head over to GitHub,
</a>
you can read the code, check out the repository, and run it
yourself. The recipes in this cookbook are small examples that
illustrate how to use Hack to solve common and interesting problems.
</p>
</div>;
}
}

View File

@@ -0,0 +1,13 @@
<?hh // strict
require_once $_SERVER['DOCUMENT_ROOT'].'/core/funs/init.php';
final class MySecureRequest {
public function __construct(private Map<string, mixed> $GETParams) {}
public function stringParam(string $name): UNESCAPED_STRING {
invariant($this->GETParams->contains($name), 'Unknown GET param: '.$name);
$raw_string = $this->GETParams[$name];
invariant(is_string($raw_string), $name.' is not a string');
return unescaped_string($raw_string);
}
}

104
samples/Hack/Nav.hh Normal file
View File

@@ -0,0 +1,104 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
type NavItem = shape(
'name' => string,
'location' => string,
);
type NavSection = shape(
'name' => string,
'location' => ?string,
'items' => Vector<NavItem>,
);
final class :hack:nav extends :x:element {
private function getNavSections(): Vector<NavSection> {
return Vector{
shape(
'name' => 'Home',
'location' => '/',
'items' => Vector {},
),
shape(
'name' => 'GitHub',
'location' => 'http://github.com/facebook/hack-example-site',
'items' => Vector {},
),
shape(
'name' => 'Recipes',
'location' => null,
'items' => Vector {
shape(
'name' => '$_GET and $_POST',
'location' => '/recipes/get-and-post/',
),
shape(
'name' => 'Assert',
'location' => '/recipes/assert/',
),
shape(
'name' => 'DB Result',
'location' => '/recipes/db-result/',
),
shape(
'name' => 'Unescaped String',
'location' => '/recipes/unescaped-string/',
),
shape(
'name' => 'User ID',
'location' => '/recipes/user-id/',
),
},
),
};
}
private function renderNavItems(Vector<NavItem> $items): :xhp {
$render_item = $item ==>
<li>
<a class="navItem" href={$item['location']}>
{$item['name']}
</a>
</li>;
return
<x:frag>
{$items->map($render_item)->toArray()}
</x:frag>;
}
private function renderNavSection(NavSection $section): :xhp {
$section_item = <h3 class="navItem">{$section['name']}</h3>;
if ($section['location'] !== null) {
$section_item = <a href={$section['location']}>{$section_item}</a>;
}
return
<li class="navSectionItem">
{$section_item}
<ul class="navItems">
{$this->renderNavItems($section['items'])}
</ul>
</li>;
}
public function render(): :xhp {
$sections = $this->getNavSections()
->map($section ==> $this->renderNavSection($section));
return
<div class="nav">
<ul class="navSections">
{$sections->toArray()}
</ul>
</div>;
}
}

View File

@@ -0,0 +1,27 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
function getGETParams(): Map<string, mixed> {
// $_GET is not defined in code so Hack doesn't know about it and you can't
// use it in strict mode. You can interact with it outside of strict mode,
// though.
return Map::fromArray($_GET);
}
function getPOSTParams(): Map<string, mixed> {
// Same deal with $_POST and other magically defined globals
return Map::fromArray($_POST);
}
// Same deal with $_SERVER
function isGET(): bool {
return $_SERVER['REQUEST_METHOD'] === 'GET';
}

93
samples/Hack/Recipe.hh Normal file
View File

@@ -0,0 +1,93 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/standard-page/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/core/myxhp/init.php';
abstract class Recipe extends GetController {
use StandardPage;
abstract protected function getName(): string;
abstract protected function getFilenames(): Vector<string>;
abstract protected function getDocs(): Vector<(string, string)>;
protected function getDescription(): ?string {
return null;
}
final protected function getTitle(): string {
return $this->getName().' - Hack Cookbook';
}
final protected function renderMainColumn(): :xhp {
$main_column =
<x:frag>
<h1>{$this->getName()}</h1>
</x:frag>;
$description = $this->getDescription();
if ($description !== null) {
$main_column->appendChild(<p>{$description}</p>);
}
foreach ($this->getFilenames() as $filename) {
$file =
<div class="file">
<div class="filename">{$filename}</div>
<phpfile filename={$filename}/>
</div>;
$main_column->appendChild($file);
}
$recipe = $this;
if ($recipe instanceof RecipeWithDemo) {
try {
$result = $recipe->getDemoResult();
} catch (Exception $e) {
$result = sprintf(
"Demo threw an %s:\n%s",
get_class($e),
$e->getMessage(),
);
}
$result = explode("\n", trim($result));
$result = array_map($x ==> <x:frag>{$x}<br/></x:frag>, $result);
$demo =
<x:frag>
<div class="demo" id="demo">
<h3>Demo</h3>
{$recipe->getDemoXHP()}
<div class="filename">{$recipe->getDemoFilename()}</div>
<phpfile filename={$recipe->getDemoFilename()}/>
<div class="filename">Output</div>
<div class="demoResult">
{$result}
</div>
</div>
</x:frag>;
$main_column->appendChild($demo);
}
if (!$this->getDocs()->isEmpty()) {
$render_doc_link = function($doc) {
list($name, $link) = $doc;
$link = "http://hhvm.com/manual/en/$link.php";
return <li><a href={$link}>{$name}</a></li>;
};
$main_column->appendChild(
<div class="docs">
<h3>Relevant Official Documentation</h3>
<ul>
{$this->getDocs()->map($render_doc_link)->toArray()}
</ul>
</div>
);
}
return $main_column;
}
}

View File

@@ -0,0 +1,16 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
interface RecipeWithDemo {
public function getDemoFilename(): string;
public function getDemoResult(): string;
public function getDemoXHP(): ?:xhp;
}

15
samples/Hack/Request.hh Normal file
View File

@@ -0,0 +1,15 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class Request {
public function __construct(private Map<string, mixed> $params) {}
}

View File

@@ -0,0 +1,81 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
trait StandardPage {
require extends Controller;
abstract protected function renderMainColumn(): :xhp;
protected function getExtraCSS(): Set<string> {
return Set {};
}
protected function getExtraJS(): Set<string> {
return Set {};
}
final protected function getCSS(): Set<string> {
return (Set {
'/css/base.css',
})->addAll($this->getExtraCSS());
}
final protected function getJS(): Set<string> {
return (Set {
})->addAll($this->getExtraJS());
}
final private function renderHeader(): :xhp {
return
<div class="hackHeader">
<div class="width">
<a href="http://hacklang.org/">
<div class="logo">Hack</div>
</a>
<div class="headerNav">
<ul>
<li>
<a href="http://hacklang.org/install/">Install</a>
</li>
<li>
<a href="http://hacklang.org/tutorial/">Tutorial</a>
</li>
<li>
<a href="/">Cookbook</a>
</li>
<li>
<a href="http://hhvm.com/manual">Docs</a>
</li>
<li>
<a href="http://github.com/facebook/hhvm">GitHub</a>
</li>
<li>
<a href="http://hhvm.com/">HHVM</a>
</li>
</ul>
</div>
</div>
</div>;
}
final protected function render(): :xhp {
return
<div>
{$this->renderHeader()}
<div class="width">
<div class="mainContainer">
<div class="mainColumn">{$this->renderMainColumn()}</div>
<hack:nav/>
</div>
</div>
</div>;
}
}

View File

@@ -0,0 +1,46 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/funs/init.php';
abstract class MyRequest {
abstract public function getParams(): Map<string, mixed>;
// Throws when things go wrong
public function intParamX(string $name): int {
$params = $this->getParams();
invariant($params->contains($name), sprintf('Unknown param: %s', $name));
$param = $params[$name];
invariant(is_numeric($param), sprintf('Param %s is not an int', $name));
return (int)$param;
}
// A lenient version
public function intParam(string $name): ?int {
$params = $this->getParams();
if (!$params->contains($name)) { return null; }
$param = $params[$name];
if (!is_numeric($param)) { return null; }
return (int)$param;
}
}
final class MyGETRequest extends MyRequest {
public function getParams(): Map<string, mixed> {
return getGETParams();
}
}
final class MyPOSTRequest extends MyRequest {
public function getParams(): Map<string, mixed> {
return getPOSTParams();
}
}

View File

@@ -0,0 +1,16 @@
<?hh // strict
// Outside of this file, no one knows that UNESCAPED_STRING is a string
newtype UNESCAPED_STRING = string;
// This is how we initially taint a string.
function unescaped_string(string $s): UNESCAPED_STRING {
return $s;
}
// This is the only thing you can do with an UNESCAPED_STRING (other than pass
// it around)
function escape_unescaped_string(UNESCAPED_STRING $s): string {
// Your use case will decide how you want to escape your strings
return sprintf('Escaped ---> "%s" <--- Escaped', $s);
}

View File

@@ -0,0 +1,59 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class UnescapedStringRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'Unescaped string';
}
<<Override>>
protected function getDescription(): ?string {
return 'Forgetting to properly escape the strings you get from your users '.
'can lead to serious security holes. Hack can help by forcing you to '.
'escape these strings before using them as strings.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'UnescapedString.php',
'MySecureRequest.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector{
tuple('Opaque Type Aliasing', 'hack.typealiasing.opaquetypealiasing'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return unescaped_string_main();
}
public function getDemoXHP(): ?:xhp {
$url = '/recipes/unescaped-string/';
return
<x:frag>
Try setting the myStrParam GET param to something nice and innocent with this button...
<div>
<a href={"$url?myStrParam='); DROP TABLE important_stuff; --#demo"} class="button">GET myStrParam=Hello world</a>
</div>
</x:frag>;
}
}

33
samples/Hack/UserID.hh Normal file
View File

@@ -0,0 +1,33 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/funs/init.php';
// Outside of this file, no one knows that these types are ints. They do know
// that USER_ID is an ID and COW_ID is an ID
newtype ID = int;
newtype USER_ID as ID = ID;
newtype COW_ID as ID = ID;
function assert_user_id(int $x): USER_ID {
// Everyone knows all user ids are odd
invariant($x % 2, sprintf('Invalid user ID: %d', $x));
return $x;
}
function assert_cow_id(int $x): COW_ID {
// Everyone knows all cow ids are even
invariant($x % 2 === 0, sprintf('Invalid cow ID: %d', $x));
return $x;
}
function id_to_int(ID $id): int {
return $id;
}

View File

@@ -0,0 +1,54 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class UserIDRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'User ID';
}
<<Override>>
protected function getDescription(): ?string {
return 'Protect your user IDs from being confused with normal ints';
}
protected function getFilenames(): Vector<string> {
return Vector {
'UserID.php',
'UsingUserID.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector {
tuple('Opaque Type Aliasing', 'hack.typealiasing.opaquetypealiasing'),
tuple(
'Opaque Type Aliasing with Constraints',
'hack.typealiasing.opaquewithconstraints',
),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return user_id_main();
}
public function getDemoXHP(): ?:xhp {
return null;
}
}

View File

@@ -0,0 +1,22 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
function get_something_string(ID $id, string $something): string {
return sprintf("Awesome %s #%d\n", $something, id_to_int($id));
}
function get_user_string(USER_ID $id): string {
return get_something_string($id, 'user');
}
function get_cow_string(COW_ID $id): string {
return get_something_string($id, 'cow');
}

43
samples/Hack/error.hh Normal file
View File

@@ -0,0 +1,43 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class TypehintViolationException extends Exception {
}
function setup_errors(): void {
set_error_handler('handle_error', E_ALL);
}
/**
* I want to turn failed typehints into exceptions so that I can handle them in
* my example code
*/
function handle_error(
$errno,
$errstr,
$errfile,
$errline,
$errcontext = array(),
$errtrace = array(),
): bool {
if (E_RECOVERABLE_ERROR == $errno) {
// Transform typehint failures into an exception.
if (strpos($errstr, 'must be an instance of ') !== false) {
throw new TypehintViolationException($errstr);
}
// Transform nullable type violations to exceptions.
if ((strpos($errstr, 'must be of type ?') !== false) &&
(strpos($errstr, 'Value returned from') === false)) {
throw new TypehintViolationException($errstr);
}
}
return false;
}

32
samples/Hack/funs.hh Normal file
View File

@@ -0,0 +1,32 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/**
* This file contains a bunch of php stubs for functions that have been added
* to hhvm (though aren't in a release yet). These are important because the
* Hack typechecker can understand them
*/
class InvariantViolationException extends Exception {}
function invariant(mixed $test, string $message): void {
if (!$test) {
invariant_violation($message);
}
}
function invariant_violation(string $message): void {
throw new InvariantViolationException($message);
}
function class_meth(string $class, string $method) {
return array($class, $method);
}

32
samples/Hack/funs.php Normal file
View File

@@ -0,0 +1,32 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/**
* This file contains a bunch of php stubs for functions that have been added
* to hhvm (though aren't in a release yet). These are important because the
* Hack typechecker can understand them
*/
class InvariantViolationException extends Exception {}
function invariant(mixed $test, string $message): void {
if (!$test) {
invariant_violation($message);
}
}
function invariant_violation(string $message): void {
throw new InvariantViolationException($message);
}
function class_meth(string $class, string $method) {
return array($class, $method);
}

14
samples/Hack/index.hh Normal file
View File

@@ -0,0 +1,14 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once 'HomeController.php';
HomeController::go($_GET);

31
samples/Hack/phpfile.hh Normal file
View File

@@ -0,0 +1,31 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
final class :phpfile extends :x:primitive {
category %flow;
attribute string filename;
/**
* Ok, I'll admit this is kind of gross. I don't really want to implement
* syntax highlighting, so I'm relying on the built-in PHP support. XHP
* makes html strings sort of difficult to use (which is good cause they're
* dangerous). Anyway, this is one way around it :)
*/
protected function stringify(): string {
return
'<div class="code">'.
(string)highlight_file($this->getAttribute('filename'), /*ret*/ true).
'</div>';
}
}

14
samples/Hack/startup.hh Normal file
View File

@@ -0,0 +1,14 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
function startup(): void {
setup_errors();
}

View File

@@ -0,0 +1,68 @@
Scriptname CAMTEST_OverShoulderME extends activemagiceffect
{Play with camera effects}
;--=== Imports ===--
Import Utility
Import Game
;--=== Properties ===--
Actor Property PlayerRef Auto
ActorBase Property CAMTEST_CameraActor Auto
;--=== Variables ===--
Actor Player
Actor Camera
Actor Target
Float PosX
Float PosY
Float PosZ
Float SpeedMult
ObjectReference Mist
ObjectReference Fog
;--=== Events ===--
Event OnInit()
Player = PlayerRef
EndEvent
Event onEffectStart(Actor akTarget, Actor akCaster)
Camera = Player.PlaceActorAtMe(CAMTEST_CameraActor)
Camera.EnableAI(False)
Camera.SetScale(0.1)
Camera.TranslateTo(Player.X + 40,Player.Y,Player.Z,0,0,0,800,30)
DisablePlayerControls(abMovement = true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abActivate = true, abJournalTabs = false)
SetPlayerAIDriven(True)
ForceThirdPerson()
SetHUDCartMode()
SetInChargen(True, True, False)
SetCameraTarget(Camera)
ForceFirstPerson()
Wait(1)
Camera.SplineTranslateTo(Player.X + 4000,Player.Y,Player.Z + 1000,15,0,Camera.GetHeadingAngle(Player) + Camera.GetAngleZ(),1800,800,100)
; Camera.SetLookAt(Player)
Wait(10)
Camera.SplineTranslateTo(Player.X + 1000,Player.Y - 500,Player.Z + 500,25,0,Camera.GetHeadingAngle(Player) + Camera.GetAngleZ(),1800,800,100)
Wait(10)
SetHUDCartMode(False)
SetCameraTarget(Player)
SetInChargen(False, False, False)
EnablePlayerControls()
SetPlayerAIDriven(False)
EndEvent
Event onUpdate()
EndEvent
Event onEffectFinish(Actor akTarget, Actor akCaster)
EndEvent
;--=== Functions ===--

View File

@@ -0,0 +1 @@
Scriptname vMFX_FXPlugin extends Quest

View File

@@ -0,0 +1,120 @@
Scriptname vSCM_MetaQuestScript extends Quest
{Do initialization and track variables for scripts}
;--=== Imports ===--
Import Utility
Import Game
;--=== Properties ===--
Actor Property PlayerRef Auto
Float Property ModVersion Auto Hidden
String Property ModName = "Smarter Combat Music" Auto Hidden
Message Property vSCM_ModLoadedMSG Auto
Message Property vSCM_ModUpdatedMSG Auto
;--=== Variables ===--
Float _CurrentVersion
String _sCurrentVersion
Bool _Running
Float _ScriptLatency
Float _StartTime
Float _EndTime
;--=== Events ===--
Event OnInit()
If ModVersion == 0
DoUpkeep(True)
EndIf
EndEvent
Event OnReset()
Debug.Trace("SCM: Metaquest event: OnReset")
EndEvent
Event OnGameReloaded()
Debug.Trace("SCM: Metaquest event: OnGameReloaded")
EndEvent
;--=== Functions ===--
Function DoUpkeep(Bool DelayedStart = True)
;FIXME: CHANGE THIS WHEN UPDATING!
_CurrentVersion = 0.01
_sCurrentVersion = GetVersionString(_CurrentVersion)
String sErrorMessage
If DelayedStart
Wait(RandomFloat(2,4))
EndIf
Debug.Trace("SCM: " + ModName)
Debug.Trace("SCM: Performing upkeep...")
Debug.Trace("SCM: Loaded version is " + GetVersionString(ModVersion) + ", Current version is " + _sCurrentVersion)
If ModVersion == 0
Debug.Trace("SCM: Newly installed, doing initialization...")
DoInit()
If ModVersion == _CurrentVersion
Debug.Trace("SCM: Initialization succeeded.")
Else
Debug.Trace("SCM: WARNING! Initialization had a problem!")
EndIf
ElseIf ModVersion < _CurrentVersion
Debug.Trace("SCM: Installed version is older. Starting the upgrade...")
DoUpgrade()
If ModVersion != _CurrentVersion
Debug.Trace("SCM: WARNING! Upgrade failed!")
Debug.MessageBox("WARNING! " + ModName + " upgrade failed for some reason. You should report this to the mod author.")
EndIf
Debug.Trace("SCM: Upgraded to " + _CurrentVersion)
vSCM_ModUpdatedMSG.Show(_CurrentVersion)
Else
Debug.Trace("SCM: Loaded, no updates.")
;CheckForOrphans()
EndIf
CheckForExtras()
UpdateConfig()
Debug.Trace("SCM: Upkeep complete!")
EndFunction
Function DoInit()
Debug.Trace("SCM: Initializing...")
_Running = True
ModVersion = _CurrentVersion
vSCM_ModLoadedMSG.Show(_CurrentVersion)
EndFunction
Function DoUpgrade()
_Running = False
If ModVersion < 0.01
Debug.Trace("SCM: Upgrading to 0.01...")
ModVersion = 0.01
EndIf
_Running = True
Debug.Trace("SCM: Upgrade complete!")
EndFunction
Function UpdateConfig()
Debug.Trace("SCM: Updating configuration...")
Debug.Trace("SCM: Updated configuration values, some scripts may update in the background!")
EndFunction
String Function GetVersionString(Float fVersion)
Int Major = Math.Floor(fVersion) as Int
Int Minor = ((fVersion - (Major as Float)) * 100.0) as Int
If Minor < 10
Return Major + ".0" + Minor
Else
Return Major + "." + Minor
EndIf
EndFunction
Function CheckForExtras()
EndFunction

View File

@@ -0,0 +1,19 @@
WarpPreset {
*new {|path|
if(path.notNil) {
^Object.readArchive(path);
};
^super.new.init();
}
init {
}
save {
Dialog.savePanel({|path|
this.writeArchive(path);
});
}
}

View File

@@ -0,0 +1,286 @@
WarpTate {
classvar <numSections = 8;
// classvar <sectionDur = 3 * 60;
classvar <sectionDur = 60;
var <sensorKeys;
var <clock;
var <tempo;
var <>tempoChannel;
var <>tempoControl;
var <out;
var <tracks;
var <>sections;
var <availableControls;
var <controls;
var <sensorVals;
var <sensorPrevs;
var <sensorMins;
var <sensorMaxs;
var <>sensorMinAdj;
var <>sensorMaxAdj;
var <doAdjusts;
var <playRout;
*new {
^super.new.init;
}
init {
tempo = 120;
tempoChannel = 15;
tempoControl = 3;
clock = TempoClock.default
.tempo_(2)
.permanent_(true);
MIDIClient.init;
out = MIDIOut.newByName("IAC Driver", "Bus 1");
out.latency = 0;
tracks = IdentityDictionary[];
sections = Array.newClear(WarpTate.numSections);
// sections is a List of IdentityDictionary to be mapped to
// WarpTrack settings var
// e.g. List[IdentityDictionary[
// '303_1' -> IdentityDictionary['notes' -> List[42]],
// '808_1' -> IdentityDictionary['notes' -> List[24]]
// ]
// ]
sensorKeys = ['303a', '303b', '808a', '808b'];
// channel 16 reserved for tempo changes
availableControls = 15.collect {|channel|
(0..120).reject({|item, i|
[ 0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 64, 65, 66, 67, 68,
69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 84, 91, 92, 93, 94,
95, 96, 97, 98, 99, 100, 102 ].includes(item)
});
};
controls = (0..127).collect { IdentityDictionary[] };
this.addOSCdefs();
CmdPeriod.add({this.stop});
}
tempo_ {|argTempo|
if(argTempo >= 50 && argTempo <= 177) {
tempo = argTempo;
clock.tempo = tempo / 60;
out.control(tempoChannel, tempoControl, tempo - 50);
} {
"Tempo out of Logic's range :(".postln;
};
}
addTrack {|trackKey, channel, type|
tracks[trackKey] = WarpTrack(this, trackKey, channel, type);
^tracks[trackKey];
}
loadTrack {|preset, checkAvailable|
var track = WarpTrack.load(this, preset, checkAvailable),
trackKey = track.settings['key'];
tracks[trackKey] = track;
^tracks[trackKey];
}
readTrack {|path|
var track = WarpTrack.read(this, path),
trackKey = track.settings['key'];
tracks[trackKey] = track;
^tracks[trackKey];
}
removeTrack {|trackKey|
tracks[trackKey].allOff();
tracks[trackKey] = nil;
}
removeAllTracks {
tracks = IdentityDictionary[];
}
on {|trackKey, note|
tracks[trackKey].on(note);
}
off {|trackKey, note|
tracks[trackKey].off(note);
}
hit {|trackKey, note=60, vel=127, dur=1|
tracks[trackKey].hit(note, vel, dur);
}
noteOn {|midiChannel, note, vel|
out.noteOn(midiChannel, note, vel);
}
noteOff {|midiChannel, note, vel|
out.noteOff(midiChannel, note, vel);
}
control {|midiChannel, num, val|
out.control(midiChannel, num, val);
}
isControlAvailable {|channel, controlNum|
^controls[channel].keys.includes(controlNum.asSymbol).not;
}
setControl {|channel, num, key|
controls[channel][num.asSymbol] = key;
availableControls[channel].remove(num);
}
assign {|trackKey, paramKey, controlNum, learn=false|
var channel = tracks[trackKey].settings['midiChannel'];
if(controlNum.notNil && this.isControlAvailable(channel, controlNum)) {
tracks[trackKey].assign(paramKey, controlNum, learn);
availableControls[channel].removeAt(0);
} {
if(availableControls[channel].size > 0) {
tracks[trackKey].assign(paramKey, availableControls[channel][0], learn);
availableControls[channel].removeAt(0);
} {
"no controls left!".postln;
};
};
"Don't forget to turn off MIDI learn".postln
}
setParam {|trackKey, paramKey, val|
var track, param;
if((track = tracks[trackKey]).notNil) {
if(track.params[paramKey].notNil) {
track.setParam(paramKey, val);
} {
"paramKey doesn't exist".postln;
};
} {
"track key doesn't exist".postln;
};
}
// sec takes IdentityDictionarys of WarpTrack settings
addSection {|index, tempo=120, presets|
// Add section with tempo
sections[index] = IdentityDictionary[
'tempo' -> tempo,
'tracks' -> presets
];
presets.do {|preset, i|
// create track if there ain't one with this key
if(tracks.includesKey(preset['key']).not) {
this.loadTrack(preset, true);
};
// store the preset
// sections[index]['tracks'][preset['key']] = preset;
};
^sections;
}
play {
if(sections.any {|item, i| item.notNil; }) {
playRout = Routine {
inf.do {|i|
sections.do {|section|
if(section.notNil) {
if(i !== 0) {
tracks.do {|track|
track.allOff();
};
this.removeAllTracks();
};
this.tempo = section['tempo'];
section['tracks'].do {|track, i|
var newTrack = this.loadTrack(track, false);
newTrack.play();
};
sectionDur.wait;
};
};
}
};
clock.playNextBar(playRout);
} {
"no sections added!".postln;
};
}
stop {
playRout.stop;
tracks.do {|track|
track.allOff();
out.allNotesOff(track.settings['midiChannel']);
}
}
addOSCdefs {
sensorVals = 0!sensorKeys.size;
sensorPrevs = 0!sensorKeys.size;
sensorMins = 9999!sensorKeys.size;
sensorMaxs = 0!sensorKeys.size;
sensorMinAdj = sensorMinAdj ?? { 0.005 };
sensorMaxAdj = sensorMaxAdj ?? { 0.01 };
doAdjusts = false!sensorKeys.size;
sensorKeys.do {|sensorKey, i|
OSCdef(("sensor_" ++ sensorKey).asSymbol, {|msg, time, addr, recvPort|
var val = msg[1];
sensorPrevs[i] = sensorVals[i];
sensorVals[i] = val;
if(doAdjusts[i]) {
sensorMins[i] = min(val, sensorMins[i]);
sensorMaxs[i] = max(val, sensorMaxs[i]);
if(val < sensorMaxs[i]) {
sensorMaxs[i] = sensorMaxs[i] - sensorMaxAdj;
};
if(val > sensorMins[i]) {
sensorMins[i] = sensorMins[i] + sensorMinAdj;
};
} {
val = val.clip(sensorMins[i], sensorMaxs[i]);
};
tracks.do {|track, j|
if(track.settings['sensorFuncs'].includesKey(sensorKey)) {
track.sensor(
sensorKey,
val.linlin(
sensorMins[i],
sensorMaxs[i],
127,
0
)
);
};
}
}, ("/prox/" ++ sensorKey).asSymbol);
}
}
}

View File

@@ -0,0 +1,263 @@
WarpTrack {
classvar <defaults;
var <parent;
var <settings;
*initClass {
defaults['303_1'] = defaults['303'].copy;
defaults['303_1']['paramControls'].putPairs([
'Bus 1', 46,
'Bus 2', 45,
'Bus 3', 48,
'echovol', 47
]);
defaults['303_1']['params'].putPairs([
'Bus 1', 0,
'Bus 2', 0,
'Bus 3', 0,
'echovol', 0
]);
defaults['303_2'] = defaults['303_1'].copy;
defaults['303_2']['paramControls'].putPairs([
]);
defaults['303_2']['params'].putPairs([
]);
defaults['808_1'] = defaults['808'].copy;
defaults['808_1']['paramControls'].putPairs([
'bitcrusher', 88,
'Send 1', 89,
'Send 2', 90,
'Send 3', 101
]);
defaults['808_1']['params'].putPairs([
'bitcrusher', 0,
'Send 1', 0,
'Send 2', 0,
'Send 3', 0
]);
defaults['808_2'] = defaults['808_1'].copy;
defaults['808_2']['paramControls'].putPairs([]);
defaults['808_2']['params'].putPairs([]);
}
*new {|argParent, argKey, argMidiChannel, argType|
^super.new.init(argParent, argKey, argMidiChannel, argType);
}
*read {|argParent, path|
^super.new.init(argParent).readPreset(path);
}
*load {|argParent, preset, checkAvailable|
^super.new.init(argParent).loadPreset(preset, checkAvailable);
}
init {|argParent, argKey, argMidiChannel, argType|
parent = argParent;
settings = IdentityDictionary[
'key' -> argKey,
'midiChannel' -> argMidiChannel,
'notes' -> Set[],
'params' -> IdentityDictionary[],
'paramControls' -> IdentityDictionary[],
'patternTrack' -> true,
'sensorFuncs' -> IdentityDictionary[]
];
if(argType.notNil) {
settings['type'] = argType;
if(WarpTrack.defaults.keys.includes(argType)) {
['paramControls', 'params'].do {|key, i|
settings[key] = WarpTrack.defaults[argType][key];
}
};
this.initParams();
};
}
on {|note|
var clock = parent.clock;
var sub = 1 / (parent.clock.tempo * 16); // one sub division
clock.schedAbs(clock.nextBar - sub, {
if(settings['patternTrack']) {
this.allOff();
} {
this.off(note);
};
});
parent.clock.playNextBar({
settings['notes'].add(note);
parent.noteOn(settings['midiChannel'], note, 127);
});
}
off {|note|
// settings['notes'].remove(note);
parent.noteOff(settings['midiChannel'], note, 0);
}
hit {|note=60, vel=127, dur=1, quant=0|
{
parent.noteOn(settings['midiChannel'], note, vel);
dur.wait;
parent.noteOff(settings['midiChannel'], note, vel);
}.fork(parent.clock, quant:quant);
}
allOff {
settings['notes'].do {|note, i|
this.off(note);
};
}
assign {|paramKey, num, learn=false, init=true, checkAvailable=true|
if(num.notNil) {
this.assignAll(IdentityDictionary[paramKey -> num], learn, init, checkAvailable);
} {
parent.assign(settings['key'], paramKey, nil, learn);
};
}
assignAll {|paramControls, learn=false, init=true, checkAvailable=true|
var action = {
var channel = settings['midiChannel'];
paramControls.keysValuesDo { |paramKey, num|
if(checkAvailable.not ||
(checkAvailable && parent.isControlAvailable(channel, num))) {
settings['paramControls'][paramKey] = num;
if(init) {
settings['params'][paramKey] = 0;
};
parent.setControl(channel, num, paramKey);
if(learn) {
parent.control(channel, num, 127);
0.05.wait;
parent.control(channel, num, 0);
};
paramKey ++ " assigned to controlNum " ++ num;
} {
("this controlNum " ++ num ++ " is already assigned!").postln;
};
};
};
if(learn) {
action.fork;
} {
action.();
};
}
initParams {
settings['params'].keysValuesDo { |key, value|
this.setParam(key, value);
};
settings['paramControls'].keysValuesDo { |key, value|
parent.setControl(settings['midiChannel'], value, key);
};
}
setParam {|paramKey, val, quant|
var func = {
parent.control(
settings['midiChannel'],
settings['paramControls'][paramKey],
val
);
settings['params'][paramKey] = val;
};
if(quant.notNil) {
{
func.();
}.fork(parent.clock, quant:quant);
} {
func.();
};
}
readPreset {|path, checkAvailable=true|
this.loadPreset(Object.readArchive(path), checkAvailable);
}
loadPreset {|preset, checkAvailable=true|
// copy all settings except notes and paramControls
preset.keys.reject({|settingKey, i|
['notes', 'paramControls'].includes(settingKey);
}).do {|presetKey, i|
settings[presetKey] = preset[presetKey];
};
// copy notes if it's a patternTrack
if(preset['patternTrack']) {
settings['notes'] = preset['notes'];
};
// assign all without learn or init
this.assignAll(
preset['paramControls'],
false,
false,
checkAvailable
);
this.initParams();
// if(settings['notes'].size > 0) {
// this.on(settings['notes'].asArray[0]);
// };
}
sensor {|sensorKey, val|
settings['sensorFuncs'][sensorKey].do {|func, i|
func.(this, val);
}
}
addFunc {|sensorKey, funcKey, func|
if(parent.sensorKeys.includes(sensorKey)) {
if(settings['sensorFuncs'].includesKey(sensorKey).not) {
settings['sensorFuncs'][sensorKey] = IdentityDictionary[];
};
settings['sensorFuncs'][sensorKey][funcKey] = func;
} {
"parent doesn't have that sensor key".postln;
};
}
removeFunc {|sensorKey, funcKey|
settings['sensorFuncs'][sensorKey].removeAt(funcKey);
if(settings['sensorFuncs'][sensorKey].isEmpty) {
settings['sensorFuncs'].removeAt(sensorKey);
};
}
availableControls {
^parent.availableControls[settings['midiChannel']].copy;
}
save {
Dialog.savePanel({|path|
settings.writeArchive(path);
});
}
play {
if(settings['patternTrack'] && settings['notes'].notEmpty) {
this.on(settings['notes'].choose);
};
}
}

View File

@@ -0,0 +1,127 @@
WarpUtil {
var <>parent;
var <curSensor;
var <win;
var <texts;
var <sensorSlider;
var <sliders;
var <updateRout;
*new {|argParent|
^super.new.init(argParent);
}
init {|argParent|
parent = argParent;
texts = IdentityDictionary[];
this.makeView();
this.startUpdate();
}
calibrate {
{
parent.doAdjusts.size.do {|i|
parent.sensorMaxs[i] = 0;
parent.sensorMins[i] = 9999;
parent.doAdjusts[i] = true;
};
sliders.do {|slider, i|
if(parent.sensorKeys[i] !== curSensor) {
slider.valueAction_(0);
0.1.wait;
slider.valueAction_(1);
};
}
}.fork(AppClock);
}
stopCalibrate {
parent.doAdjusts.size.do {|i|
parent.doAdjusts[i] = false;
}
}
makeView {
var width = 370;
if(win.notNil) {
win.close;
};
win = Window("Sensor Inspector", Rect(256, 10, width, 424)).front;
win.view.addFlowLayout;
['sensorVals', 'sensorPrevs', 'sensorMins', 'sensorMaxs'].do {|label, i|
StaticText(win, (width * 0.5)@20)
.string_(label.asString);
win.view.decorator.nextLine;
texts[label] = StaticText(win, (width / 2)@40);
if(curSensor.notNil) {
texts[label].string_(
"\t" ++ parent.perform(label).at(
parent.sensorKeys.indexOf(curSensor)
);
);
};
win.view.decorator.nextLine;
};
sensorSlider = EZSlider(win, 280@20, label: curSensor.asString);
sliders = parent.sensorKeys.collect { |sensorKey, i|
EZSlider(win, 280@20, label: sensorKey.asString)
.action_({|ez|
NetAddr.localAddr.sendMsg(
"/prox/" ++ sensorKey,
ez.value * 100
);
});
};
}
startUpdate {
updateRout = Routine {
inf.do {|i|
var index;
if(curSensor.notNil) {
index = parent.sensorKeys.indexOf(curSensor);
['sensorVals', 'sensorPrevs', 'sensorMins',
'sensorMaxs'].do {|label, i|
texts[label]
.string_("\t" ++ parent.perform(label)[index]);
};
sensorSlider.value = parent.sensorVals[index].linlin(
parent.sensorMins[index],
parent.sensorMaxs[index],
0,
1
);
};
0.05.wait;
}
};
updateRout.play(AppClock);
}
stopUpdate {
updateRout.stop();
}
curSensor_ {|argCurSensor|
curSensor = argCurSensor;
this.makeView();
}
}

View File

@@ -304,6 +304,14 @@ class TestBlob < Test::Unit::TestCase
# Debian packaging
assert blob("debian/cron.d").vendored?
# Minified JavaScript and CSS
assert blob("foo.min.js").vendored?
assert blob("foo.min.css").vendored?
assert blob("foo-min.js").vendored?
assert blob("foo-min.css").vendored?
assert !blob("foomin.css").vendored?
assert !blob("foo.min.txt").vendored?
# Prototype
assert !blob("public/javascripts/application.js").vendored?
assert blob("public/javascripts/prototype.js").vendored?

View File

@@ -40,25 +40,25 @@ class TestHeuristcs < Test::Unit::TestCase
match = Language.detect(blob)
assert_equal Language["Objective-C"], match
end
def test_pl_prolog_by_heuristics
languages = ["Perl", "Prolog"]
results = Heuristics.disambiguate_pl(fixture("Prolog/turing.pl"), languages)
assert_equal Language["Prolog"], results.first
end
def test_pl_perl_by_heuristics
languages = ["Perl", "Prolog"]
results = Heuristics.disambiguate_pl(fixture("Perl/perl-test.t"), languages)
assert_equal Language["Perl"], results.first
end
def test_ecl_prolog_by_heuristics
languages = ["ECL", "Prolog"]
results = Heuristics.disambiguate_ecl(fixture("Prolog/or-constraint.ecl"), languages)
assert_equal Language["Prolog"], results.first
end
def test_ecl_ecl_by_heuristics
languages = ["ECL", "Prolog"]
results = Heuristics.disambiguate_ecl(fixture("ECL/sample.ecl"), languages)
@@ -77,6 +77,12 @@ class TestHeuristcs < Test::Unit::TestCase
assert_equal Language["IDL"], results.first
end
def test_asc_asciidoc_by_heuristics
languages = ["AGS Script", "AsciiDoc"]
results = Heuristics.disambiguate_asc(fixture("AsciiDoc/list.asc"), languages)
assert_equal Language["AsciiDoc"], results.first
end
def test_ts_typescript_by_heuristics
languages = ["TypeScript", "XML"]
results = Heuristics.disambiguate_ts(fixture("TypeScript/classes.ts"), languages)
@@ -98,4 +104,22 @@ class TestHeuristcs < Test::Unit::TestCase
end
end
end
def test_hack_by_heuristics
languages = ["Hack", "PHP"]
results = Heuristics.disambiguate_hack(fixture("Hack/funs.php"), languages)
assert_equal Language["Hack"], results.first
end
def test_sc_supercollider_by_heuristics
languages = ["Scala", "SuperCollider"]
results = Heuristics.disambiguate_sc(fixture("SuperCollider/WarpPreset.sc"), languages)
assert_equal Language["SuperCollider"], results.first
end
def test_sc_scala_by_heuristics
languages = ["Scala", "SuperCollider"]
results = Heuristics.disambiguate_sc(fixture("Scala/node11.sc"), languages)
assert_equal Language["Scala"], results.first
end
end

View File

@@ -119,6 +119,7 @@ class TestLanguage < Test::Unit::TestCase
assert_equal Language['VimL'], Language.find_by_alias('viml')
assert_equal Language['reStructuredText'], Language.find_by_alias('rst')
assert_equal Language['YAML'], Language.find_by_alias('yml')
assert_nil Language.find_by_alias(nil)
end
def test_groups
@@ -221,6 +222,7 @@ class TestLanguage < Test::Unit::TestCase
end
def test_find_by_name
assert_nil Language.find_by_name(nil)
ruby = Language['Ruby']
assert_equal ruby, Language.find_by_name('Ruby')
end
@@ -241,6 +243,22 @@ class TestLanguage < Test::Unit::TestCase
end
end
def test_find_by_extension
assert_equal [], Language.find_by_extension('.factor-rc')
assert_equal [], Language.find_by_extension('foo.rb')
assert_equal [Language['Ruby']], Language.find_by_extension('rb')
assert_equal [Language['Ruby']], Language.find_by_extension('.rb')
assert_equal [Language['M'], Language['Mathematica'], Language['Matlab'], Language['Mercury'], Language['Objective-C']], Language.find_by_extension('.m')
end
def test_find_all_by_extension
Language.all.each do |language|
language.extensions.each do |extension|
assert_include Language.find_by_extension(extension), language
end
end
end
def test_find_by_filename
assert_equal [Language['Shell']], Language.find_by_filename('PKGBUILD')
assert_equal [Language['Ruby']], Language.find_by_filename('foo.rb')
@@ -301,6 +319,22 @@ class TestLanguage < Test::Unit::TestCase
assert_equal 'C#', Language['c#'].name
assert_equal 'C#', Language['csharp'].name
assert_nil Language['defunkt']
assert_nil Language[nil]
end
def test_find_ignores_case
assert_equal 'AGS Script', Language['ags script'].name
assert_equal 'AGS Script', Language['ags sCRIPT'].name
end
def test_find_by_name_ignores_case
assert_equal 'AGS Script', Language.find_by_name('ags script').name
assert_equal 'AGS Script', Language.find_by_name('ags sCRIPT').name
end
def test_find_by_alias_ignores_case
refute_includes Language['AGS Script'].aliases, 'AGS'
assert_equal 'AGS Script', Language.find_by_alias('AGS').name
end
def test_name

View File

@@ -16,11 +16,11 @@ class TestSamples < Test::Unit::TestCase
warn "Samples database is out of date. Run `bundle exec rake samples`."
expected = Tempfile.new('expected.json')
expected.write Yajl::Encoder.encode(serialized, :pretty => true)
expected.write Yajl.dump(serialized, :pretty => true)
expected.close
actual = Tempfile.new('actual.json')
actual.write Yajl::Encoder.encode(latest, :pretty => true)
actual.write Yajl.dump(latest, :pretty => true)
actual.close
expected.unlink