mbklein / confstruct Goto Github PK
View Code? Open in Web Editor NEWYet another hash/struct-like configuration object for Ruby
Yet another hash/struct-like configuration object for Ruby
It looks like there's some incompatibility between Ruby 1.8.7 and Ruby 1.9.3 when trying to YAML dump the confstruct configuration. A test like this breaks under 1.9.3 (when using Psych -- Sych works fine..):
describe "YAML serialization" do
subject { Confstruct::Configuration.new(@config) }
it "should dump successfully" do
@config = { :a => 1 }
yaml = YAML.dump subject # <--- fails here
result = YAML.load(yaml)
result.keys.should == subject.keys
end
end
Here's the error:
1) Confstruct::Configuration YAML serialization should dump successfully
Failure/Error: yaml = YAML.dump subject
NoMethodError:
undefined method `name' for nil:NilClass
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:25:in `block in initialize'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `yield'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `default'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `block in initialize'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `yield'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `default'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `block in initialize'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `yield'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `default'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `block in initialize'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `yield'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `default'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `block in initialize'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `yield'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `default'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:27:in `block in initialize'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `yield'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `default'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `accept'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:66:in `push'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/psych.rb:242:in `dump'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-mocks-2.11.1/lib/rspec/mocks/extensions/psych.rb:5:in `dump_with_mocks'
# ./spec/confstruct/configuration_spec.rb:26:in `block (3 levels) in <top (required)>'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:113:in `instance_eval'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:113:in `block in run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:253:in `with_around_each_hooks'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:110:in `run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:378:in `block in run_examples'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:374:in `map'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:374:in `run_examples'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:360:in `run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:361:in `block in run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:361:in `map'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:361:in `run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:28:in `map'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:28:in `block in run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/reporter.rb:34:in `report'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:25:in `run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/runner.rb:69:in `run'
# /Users/cabeer/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rspec-core-2.11.1/lib/rspec/core/runner.rb:8:in `block in autorun'
Yuck.
Travis shows all passing in master... but if I run tests myself, I get failures. Very odd and confusing. Any ideas?
Actually, Travis last ran tests 9 months ago -- I bet if it were to run tests again today with new versions of rspec and other dependencies, it would fail. I think that's what's going on.
$ bundle exec rake
/opt/rubies/ruby-2.0.0-p576/bin/ruby -I/Users/jrochkind/.gem/ruby/2.0.0/gems/rspec-core-3.1.7/lib:/Users/jrochkind/.gem/ruby/2.0.0/gems/rspec-support-3.1.2/lib /Users/jrochkind/.gem/ruby/2.0.0/gems/rspec-core-3.1.7/exe/rspec --pattern ./spec/\*\*/\*_spec.rb
FF........F.F.....F..........F....FF..*.FFF
Pending:
Confstruct::HashWithStructAccess delegation should gracefully handle being extended
# probably won't fix due to the unpredictable way ActiveSupport injects #presence()
# ./spec/confstruct/hash_with_struct_access_spec.rb:259
Failures:
1) Confstruct::Configuration should initialize empty
Failure/Error: conf.is_a?(Hash).should be_true
expected true to respond to `true?`
# ./spec/confstruct/configuration_spec.rb:7:in `block (2 levels) in <top (required)>'
2) Confstruct::Configuration should initialize properly from a nested hash with string keys
Failure/Error: conf.is_a?(Hash).should be_true
expected true to respond to `true?`
# ./spec/confstruct/configuration_spec.rb:15:in `block (2 levels) in <top (required)>'
3) Confstruct::Configuration configuration should call #after_config! when configuration is complete
Failure/Error: postconfigurator = RSpec::Mocks::Mock.new('after_config!')
NameError:
uninitialized constant RSpec::Mocks::Mock
# ./spec/confstruct/configuration_spec.rb:119:in `block (3 levels) in <top (required)>'
4) Confstruct::HashWithStructAccess should initialize empty
Failure/Error: hwsa.is_a?(Hash).should be_true
expected true to respond to `true?`
# ./spec/confstruct/hash_with_struct_access_spec.rb:7:in `block (2 levels) in <top (required)>'
5) Confstruct::HashWithStructAccess data manipulation should properly respond to #has?
Failure/Error: @hwsa.has?('github.url').should be_true
expected true to respond to `true?`
# ./spec/confstruct/hash_with_struct_access_spec.rb:70:in `block (3 levels) in <top (required)>'
6) Confstruct::HashWithStructAccess Proc values as virtual methods should only evaluate Confstruct::Deferred procs
Failure/Error: @hwsa.github.regular_proc.is_a?(Proc).should be_true
expected true to respond to `true?`
# ./spec/confstruct/hash_with_struct_access_spec.rb:195:in `block (3 levels) in <top (required)>'
7) Confstruct::HashWithStructAccess Proc values as virtual methods should allow definition of deferreds in block mode
Failure/Error: @hwsa.github.defproc.is_a?(Proc).should be_false
expected false to respond to `false?`
# ./spec/confstruct/hash_with_struct_access_spec.rb:224:in `block (3 levels) in <top (required)>'
8) Confstruct::HashWithStructAccess Proc values as virtual methods should handle i18n translations
Failure/Error: I18n = RSpec::Mocks::Mock.new('I18n')
NameError:
uninitialized constant RSpec::Mocks::Mock
# ./spec/confstruct/hash_with_struct_access_spec.rb:231:in `block (3 levels) in <top (required)>'
9) Kernel.eval_or_yield should instance_eval when the block takes no params
Failure/Error: @obj = RSpec::Mocks::Mock.new('obj')
NameError:
uninitialized constant RSpec::Mocks::Mock
# ./spec/confstruct/utils_spec.rb:5:in `block (2 levels) in <top (required)>'
10) Kernel.eval_or_yield should yield when the block takes a param
Failure/Error: @obj = RSpec::Mocks::Mock.new('obj')
NameError:
uninitialized constant RSpec::Mocks::Mock
# ./spec/confstruct/utils_spec.rb:5:in `block (2 levels) in <top (required)>'
11) Kernel.eval_or_yield should return the object when no block is given
Failure/Error: @obj = RSpec::Mocks::Mock.new('obj')
NameError:
uninitialized constant RSpec::Mocks::Mock
# ./spec/confstruct/utils_spec.rb:5:in `block (2 levels) in <top (required)>'
Deprecation Warnings:
Requiring `rspec/autorun` when running RSpec via the `rspec` command is deprecated. Called from /Users/jrochkind/code/confstruct/spec/spec_helper.rb:6:in `require'.
Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` instead. Called from /Users/jrochkind/code/confstruct/spec/confstruct/configuration_spec.rb:7:in `block (2 levels) in <top (required)>'.
If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.
2 deprecation warnings total
Finished in 0.0167 seconds (files took 0.13942 seconds to load)
43 examples, 11 failures, 1 pending
Failed examples:
rspec ./spec/confstruct/configuration_spec.rb:5 # Confstruct::Configuration should initialize empty
rspec ./spec/confstruct/configuration_spec.rb:12 # Confstruct::Configuration should initialize properly from a nested hash with string keys
rspec ./spec/confstruct/configuration_spec.rb:118 # Confstruct::Configuration configuration should call #after_config! when configuration is complete
rspec ./spec/confstruct/hash_with_struct_access_spec.rb:5 # Confstruct::HashWithStructAccess should initialize empty
rspec ./spec/confstruct/hash_with_struct_access_spec.rb:69 # Confstruct::HashWithStructAccess data manipulation should properly respond to #has?
rspec ./spec/confstruct/hash_with_struct_access_spec.rb:194 # Confstruct::HashWithStructAccess Proc values as virtual methods should only evaluate Confstruct::Deferred procs
rspec ./spec/confstruct/hash_with_struct_access_spec.rb:219 # Confstruct::HashWithStructAccess Proc values as virtual methods should allow definition of deferreds in block mode
rspec ./spec/confstruct/hash_with_struct_access_spec.rb:229 # Confstruct::HashWithStructAccess Proc values as virtual methods should handle i18n translations
rspec ./spec/confstruct/utils_spec.rb:8 # Kernel.eval_or_yield should instance_eval when the block takes no params
rspec ./spec/confstruct/utils_spec.rb:16 # Kernel.eval_or_yield should yield when the block takes a param
rspec ./spec/confstruct/utils_spec.rb:26 # Kernel.eval_or_yield should return the object when no block is given
Coverage report generated for RSpec to /Users/jrochkind/code/confstruct/coverage. 299 / 340 LOC (87.94%) covered.
/opt/rubies/ruby-2.0.0-p576/bin/ruby -I/Users/jrochkind/.gem/ruby/2.0.0/gems/rspec-core-3.1.7/lib:/Users/jrochkind/.gem/ruby/2.0.0/gems/rspec-support-3.1.2/lib /Users/jrochkind/.gem/ruby/2.0.0/gems/rspec-core-3.1.7/exe/rspec --pattern ./spec/\*\*/\*_spec.rb failed
msel-sysmac14:confstruct jrochkind$
It's not good practice to put tasks
in the lib
directory. Anything in the toplevel of the lib
directory indicates an ownership, meaning you should have registered the name as a gem. The reason is, if someone creates a project called tasks
then your use of that library namespace could come into conflict with theirs.
This one is weird edge case of some kind, but i'm not sure what kind. Here's the reproduction:
conf = Confstruct::Configuration.new
conf.configure( :top=>{:middle=>{"one"=>"two"}} )
conf.top.middle # => {"one"=>"two"}
conf.top.middle.class # => Confstruct::HashWithStructAccess
conf.top.middle.one # => nil WHAT?
conf.top.middle["one"] # => nil # uh?
conf.top.middle[:one] #=> nil
What's going on? Is "one" somehow a reserved word too? Not sure. If we change the literal to a symbol, weirdly all is well. huh?
conf = Confstruct::Configuration.new
conf.configure( :top=>{:middle=>{:one=>"two"}} )
conf.top.middle.one # => "two" # great!
Hmm, a string other than 'one'?
conf = Confstruct::Configuration.new
conf.configure( :top=>{:middle=>{"foo"=>"two"}} )
conf.top.middle # {"foo"=>"two"}
conf.top.middle.foo # => nil
Nope it's not the word 'one' I don't think.
But it doens't require three levels of nesting, one will do it with strings:
conf = Confstruct::Configuration.new
conf.configure("top" => { "bottom" => "bottom" })
conf.top # => {"bottom" => "bottom" }
conf.top.class # => Confstruct::HashWithStructAccess
conf.top.bottom # => nil
conf.top["bottom"] #=> nil
conf.top.keys # => ["bottom"] WHAT???
Ugh. Any ideas?
I'm able to do
config = Confstruct::Configuration.new do
github do
url 'http://www.github.com/mbklein/confstruct'
branch 'master'
end
end
but not
config = Confstruct::Configuration.new({:'github.url' => 'http://www.github.com/mbklein/confstruct', :'github.branch' => 'master' })
I'm getting a hash from elsewhere and would love to do the nesting that the DSL affords.
Consider this example:
conf = Confstruct::Configuration.new do
format "XML"
end
If initialised like this, conf will return empty hash. If confstruct is initialised via hash, the key is not there.
We, however, like block initialising very much, and key named 'format' is important for us. I would be very happy to see this fixed: )
With Hashie 3.4.2, this code used to work
require 'timeout'
require 'confstruct'
Confstruct::Configuration.new(timeout: 1)
Using 3.4.3, this fails with:
ArgumentError: The property timeout clashes with an existing method.
from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/extensions/mash/safe_assignment.rb:6:in `custom_writer'
from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:177:in `block in deep_update'
from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:170:in `each_pair'
from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:170:in `deep_update'
from /Users/cabeer/.gem/ruby/2.2.1/gems/hashie-3.4.3/lib/hashie/mash.rb:88:in `initialize'
from /Users/cabeer/.gem/ruby/2.2.1/gems/confstruct-1.0.2/lib/confstruct/configuration.rb:8:in `initialize'
In 3.4.3, hashie "fixed" their property/method clashing logic, but broke some of our code that had property/method conflicts. On one hand, the new behavior seems more correct. On the other, we're loading this configuration from YAML into Confstruct so we can pass it off to e.g. Faraday (which has configuration with a timeout property) with minimal transformation.
I've left a comment upstream (hashie/hashie#320), but we may want to file a real bug report if we think it's an upstream issue.
This test passes in ruby 1.8 but fails in ruby 1.9:
describe "deferred" do
subject do
Confstruct::Configuration.new({
:a => Confstruct.deferred { |c| c }
})
end
it "should work" do
subject.a.should be_a_kind_of Confstruct::Configuration
end
end
In Ruby 1.8, c
is {:a=>(deferred)}
, but in 1.9 it is nil (because the Proc isn't being implicitly call?)
BACKGROUND:
I would like to use configs with question marks (e.g. enabled?
) for booleans.
REPRO STEPS:
Define a config object with a config that has a question mark:
config = Confstruct::Configuration.new enabled?: true
EXPECTED OUTCOME:
I should be able to run this without errors and then use the config e.g.:
if config.enabled? #...
ACTUAL OUTCOME:
Code barfs:
/Users/josh/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/hashie-3.5.6/lib/hashie/extensions/mash/safe_assignment.rb:6:in 'custom_writer': The property enabled? clashes with an existing method. (ArgumentError)
Note that if I change to enabled
(without question mark) this goes away. The error message is misleading - pretty sure it's not really a clash with an existing method, as I tried other variable names, always get that error if it has a question mark, works fine otherwise.
it "should dump to yaml" do
require 'yaml'
conf = Confstruct::Configuration.new
YAML.dump(conf)
end
Fails with:
1) Confstruct::Configuration should dump to yaml
Failure/Error: YAML.dump(conf)
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/confstruct/configuration_spec.rb:15:in `block (2 levels) in <top (required)>'
It seems that repository
is ignored by default.
config = Confstruct::Configuration.new { repository 'hello' }
# => {}
h.has?('foo.bar.baz') # true if the full path to the key exists, false if it doesn't
h.lookup('foo.bar.baz') # returns the result if it exists, nil if it doesn't
Have you considered joining forces with Construct project? I was looking at both Confstruct and Construct projects today and it seems that both projects have something to offer in the creation of a superior unified project that covers the use cases of both.
Looking awesome. I like the new Deferred implementation, and thanks for #lookup! and #has? .
One feature I need that's missing. Ability to, in config DSL, add an element to a list in a nice neat way. Ie, right now already, you'd have to do something like this, not even sure this would work in block form:
configure do
some_list []
some_list << "something"
end
I'm not even sure that would work, and it's ugly for a configuration dsl.
Here's one idea I had, you may have a better one (or decide it's out of scope). Have method_missing catch anything that looks like add_*!, where the * is any string. On such a method, if the key is empty, make it an array and add the result of following value or block to it; if it's already an array (or anything that respond to "<<"), then add the result of the following value or block; if it's already something that does not respond to << then raise.
configure do
add_some_list! "foo"
add_some_list! do
foo "foo"
bar "bar"
end
end
=> { :some_list => ["foo", {:foo => "foo", :bar => "bar"} ] }
configure do
widget do
add_element! "one"
add_element! "two"
end
end
=> {:widget => {:element => ["one", "two"] }
Is there a reason "display" would be a reserved word for a key? Traced my weird bug down to that.
hash = {:display=> "display", :foo => 'foo'}
conf = Confstruct::Configuration.new( hash )
conf.foo # => 'foo'
conf.display # => #<Confstruct::Configuration:0x0000000fff4b78>nil
conf[:display] # => 'display'
Looks like 'display' is for some reason 'special'/reserved, but I am not sure why or if this is a bug. Took me a while to reproduce and figure out it really was the key 'display' that did it!
I'm trying to use Confstruct like
yaml = YAML.load_file 'application.yml'
config = Confstruct::Configuration.new yaml
When yaml contains nested hashes, it's not possible to reach inner members. But if i set inner member by hands, it works:
irb(main):001:0> require 'confstruct'
=> true
irb(main):002:0> x = {'a' => {'b' => 'c'}}
=> {"a"=>{"b"=>"c"}}
irb(main):003:0> config = Confstruct::Configuration.new x
=> {:a=>{"b"=>nil}}
irb(main):004:0> config[:a]['d'] = 'e'
=> "e"
irb(main):005:0> config
=> {:a=>{"b"=>nil, :d=>"e"}}
Given I create a Confstruct::Configuration from a Hash
When I call #presence on a deep value
Then I should get the value # or at least something behaving equally
This fails - because #presence (called for an HashWithStructAccess with ActiveSupport) will return the value converted to an OrderedHash:
$#> irb -f
# set up env
require 'rubygems'
# => true
require 'active_support/core_ext/object/blank'
# => true
require 'confstruct' # 0.2.1
# => true
# set up data
c = Confstruct::Configuration.new("a" => {"b" => {"c" => "d"}})
# => {:a=>{:b=>{:c=>"d"}}}
# access data
c["a"]["b"].class
# => Confstruct::HashWithStructAccess
# ooops!
c["a"]["b"].presence.class
# => ActiveSupport::OrderedHash
Unfortunately, the OrderedHash is not .with_indifferent_access:
# surprise! :-(
c["a"]["b"]["c"]
# => "d"
c["a"]["b"].presence["c"]
# => nil
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.