ãã®èšäºã¯Ruby Advent Calendar 2019ã®25æ¥ç®ã®èšäºã§ãã
æ¬æ¥ã¯ã¯ãªã¹ãã¹ãšããããšã§ãäŸå¹ŽãªãRubyã®æ°ããŒãžã§ã³ããªãªãŒã¹ãããæ¥ã«ãªããŸãã
æ°ããŒãžã§ã³ã®Ruby 2.7ã¯RC2ãŸã§ãã£ãŠããã®ã§ããªãªãŒã¹ã«åããŠçå®ã«é²ãã§ããããã§ãã
ðð ãããŠç¡äºã«æ¬æ¥ãªãªãŒã¹ãããŸãã!! ããã§ãšãããããŸã!!! ðð
(æ¬èšäºæçš¿æç¹ã§ã¯ãŸã ãªãªãŒã¹ã¯ãããŠããŸããã)
ããã§Ruby2.7ã®ãªãªãŒã¹ã®ãç¥ããšã³ããã¿ãŒã®ã¿ãªããã®ããŒãã¯ãŒã¯ã«æè¬ã®æ°æã¡ã蟌ããŠãRubyã®22幎ã«æž¡ãã³ãããã®æŽå²ãå¯èŠåããŠã¿ãããšæããŸãã
(2019/12/29è¿œèš)
19æ¥ç®ã®ä»£çæçš¿ã§ä»¥äžã®ç¶ç·šèšäºãæžããŸããã
ã¯ããã«
äžçªæåã®åæ©ã¯ã³ããã¿ãŒã®ã¿ãªãããæ¥ã ã©ãã ãã®ã³ããããç©ã¿éããŠããã®ããéå»ããé¡ã£ãŠèŠãŠã¿ãããšãããã®ã§ããããããRubyã®èªçã¯1993幎ãšèšãããŠããã27幎ã®éçºã®æŽå²ã®äžã§é¢ãã£ãŠããã³ããã¿ãŒã®æ°ã¯200人ãè¶ ããã®ã§åçŽãªæ£ã°ã©ããç·ã°ã©ãã§ã¯å¯èŠåãç Žç¶»ããã®ã¯ç®ã«èŠããŠããŸããã
ããã§ãFlourishããšãããµãŒãã¹ã䜿ããæé軞ãå ããæ£ã°ã©ãã®ã¢ãã¡ãŒã·ã§ã³ãå©çšããããšã§ãåžžã«ããã20ã®ã³ããã¿ãŒã®æ§åãæããããããã«ããŸãã
å®æã€ã¡ãŒãžã¯äžèšã®ããã«ãªããŸããäžã®ç»åã2019幎ãŸã§ã¢ãã¡ãŒã·ã§ã³ãããããã®äœæ¥ãè¡ãããšãæ¬èšäºã®è¶£æšã«ãªããŸãããŸãããã£ãããªã®ã§ãªãã¹ãRubyã䜿ã£ãŠãã®äœæ¥ãè¡ã£ãŠã¿ãããšæããŸãã
ããã§ã¯è¡ã£ãŠã¿ãŸãããã
ã³ããããã°ãåéãã
äœã¯ãšããããã³ããããã°ãåéããªããšå¯èŠåãã§ããŸãããããã§Rubyã®ãªããžããªãååŸããããšããå§ããããšæããŸãã
Rubyã®ãªããžããªãååŸãã
ãŸãã¯GitHubã®Rubyãªããžããªã¯ããŒã³ããŠããŸãã
git clone https://github.com/ruby/ruby.git
ãã ããäžèšã®ãªããžããªã®ããŒãžã«ã¯ã¿ã€ãã«ã«ä»¥äžã®ããã«[mirror]
ãšä»ããŠããŸãã
The Ruby Programming Language [mirror]
ããã¯ã©ãããããšããšãããšãå®ã¯Rubyã¯æ£åŒãªRubyã®Gitãªããžããªã¯GitHubãšã¯å¥ã®Gitãªããžããªã§ç®¡çãããŠããŸãããŸãããã以åã«Rubyã®éçºã¯2019幎4æ22æ¥ãŸã§SVNãªããžããªã§ç®¡çãããŠãããäžéšã®ãã©ã³ãã¯ãŸã ãã¡ãã§éçºãç¶ããŠãããšããäºå®ããããŸã1ã
ãã®èŸºã®çµç·¯ã¯ã什åæ代ã®Rubyã³ã¢éçºãã«æžããŠãããŸãããæŽå²ã®é·ããããã¯ãã¯ããŒãžã§ã³ç®¡çã·ã¹ãã ãå€ããã®ã«å€§ããªåŽåã䌎ããšããäžäŸã ãšæããŸãã
話ã¯éžããŸãããã®URLã«ã¡ãŒã«ã¢ãã¬ã¹ãèŒã£ãŠããªããš2020幎1æ1æ¥ä»¥épushãã§ããªããªãã¿ãããªã®ã§ã³ããã¿ã®æ¹ã¯ãæ°ãä»ããã ããã
Rubyã®ãªããžããªãèŠããŠã¿ã
ãªããžããªã®ã¯ããŒã³åŸã«ããããšãšèšãã°ãäžçªæåã®ã³ããããšäžçªæåŸã®ã³ããããèŠãããšã ãšæããŸãããŸãã¯æåŸã®ã³ããããgit log
ã³ãã³ãã§èŠãŠã¿ãŸãã
commit 16fddfe352828d26aaa6cdbce696e62de04511ce (HEAD -> master, origin/trunk, origin/master, origin/HEAD)
Author: Marcus Stollsteimer <sto.mar@web.de>
Date: Mon Dec 23 15:02:59 2019 +0100
[DOC] Improve readability of requirements for <=>
æåŸã®ã³ãããã¯12/23ã«è¡ãããŠããŸãã次ã«äžçªæåã®ã³ããããèŠãŠã¿ãŸããgit log
ã³ãã³ãã«--reverse
ãªãã·ã§ã³ãã€ããããšã§å
é ããã³ããããèŠãããšãã§ããŸãã
git log --reverse
äžçªæåã®ã³ãããã¯1998/1/16ã«è¡ãããããã§ãããã°ã«by cvs2svn
ãšããã®ã§ããŒãžã§ã³ç®¡çã·ã¹ãã ãCVSããSubversionã«ç§»è¡ããããã«cvs2svn
ã³ãã³ããçšããããã§ãã
commit 392296c12de9d7f9be03a8205250ba0844cb9d38
Author: (no author) <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Fri Jan 16 12:13:05 1998 +0000
New repository initialized by cvs2svn.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
commit 3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4 (tag: v1_0_r2)
Author: matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Fri Jan 16 12:13:05 1998 +0000
Initial revision
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
ãŸããã³ããããã°ã«git-svn-id
ãæ®ã£ãŠããã®ã§ããã®ãªããžããªã¯Subversionæ代ã«git-svn
ã³ãã³ããçšããŠGitHubãšåæãããŠããããšãåãããŸãããã®ãžãã®çµç·¯ããŸãšãããã®ããªãããªãšããããæ€çŽ¢ããããã³ãŸ0052å·ã«æžãããŠããŸãããGitã«ç§»è¡ããçŸåšã®ç¶æ³ãå å³ãããšä»¥äžã®ããã«ãªããŸãã
幎代 | ããŒãžã§ã³ç®¡çã·ã¹ãã |
---|---|
1993ã1998/1 | RCS/tarããŒã«? |
1998/1ã2006/12 | CVS |
2006/12 ã 2019/4 | Subversion |
2019/4 ã çŸåš | Git |
ã³ããããã°ã«æ®ã£ãŠããã®ã¯CVSã§ç®¡çããã1998幎以éãªã®ã§ãå¯èŠåã§ããã®ã¯ãã®çŽ22幎éåã®ã³ãããã«ãªããŸããæ®å¿µãªããRubyèªçããçŽ5幎éã®æŽå²ã¯å¯èŠåã§ããªãããšããäºæ¿ãã ããã
äœè å¥ã«ã³ãããæ°ãã«ãŠã³ãããŠã¿ã
次ã«å¹Žåäœã§äœè
å¥ã«ã³ãããæ°ãã«ãŠã³ãããŠã¿ãŸããåçäžã¯ã³ããããã°ããããã°ã³ãããã®æ¥ä»ãšã³ãããã®äœè
ãšã³ãããæ°ãåããã®ã§ãæåã¯ã³ããããã°ãèªåã§ããŒã¹ããŠã«ãŠã³ãããããšæã£ãŠããŸããããgit shortlog
ãšãã䟿å©ãªã³ãã³ããããããšã«æ°ã¥ããŸããã
以äžã®ã³ãã³ãã§1998幎ãã2019幎ãŸã§ã®äœè
å¥ã®ã³ãããæ°ãèŠãããšãã§ããŸãã
git shortlog -sne --no-merges --since='1998-01-01' --until='2019-12-31'
ãªãã·ã§ã³ã¯ä»¥äžã®ãšããã§ãã
ãªãã·ã§ã³ | 説æ |
---|---|
-n |
äœè ããšã®ã³ãããæ°ã§ãœãŒã |
-s |
ã³ãããæ°ã®æŠèŠã®ã¿è¡šç€º |
-e |
Eã¡ãŒã«ã¢ãã¬ã¹ã衚瀺 |
--no-merges |
ããŒãžã³ããããé€å€ |
ââsince |
éå§æ¥æ |
--until |
çµäºæ¥æ |
ããã10ã¯ä»¥äžã®ãšããã§ããïŒäœã¯ã芧ã®éãnobuããã§å§å·»ã®1äž6åã³ãããã2äœã«ããªãã«ã¹ã³ã¢ä»¥äžã®å·®ãã€ããŠå§åçãªæŠéåãèªã£ãŠããŸãã
16566 nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
4746 akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
4338 svn <svn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
2728 naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
2562 matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
2357 ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
2050 usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
1414 eban <eban@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
1176 Nobuyoshi Nakada <nobu@ruby-lang.org>
1168 kazu <kazu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
ãã äžèšã®ã³ãããæ°ã®è¡šç€ºã«ã¯å€§ããªåé¡ããããŸããåãã人ã«ã¯åãããšæãã®ã§ãããå®ã¯1äœã®nobuãããš9äœã®Nobuyoshi Nakadaããã¯åäžäººç©ã§ããããã¯äœè åãEã¡ãŒã«ã¢ãã¬ã¹ãç°ãªããšç°ãªããã®ãšããŠã«ãŠã³ããããŠããŸãããã§ãã
ãã®åé¡ã解決ããããã«ã¯åå¯ããšãã£ãŠåäžäººç©ãšæãããã³ããããéçŽããªããšãããŸãããå®ã¯git shortlog
ã«ã¯.mailmap
ãšããéçŽã®ä»çµã¿ãããã®ã§ããããããå©çšããããã«ã¯ããããåäžäººç©ã®Eã¡ãŒã«ã¢ãã¬ã¹ãã©ãããšããæ
å ±ãæã£ãŠããå¿
èŠããããŸãã
ä»åã¯ã©ã®Eã¡ãŒã«ã¢ãã¬ã¹ãåäžäººç©ããæšæž¬ãããšããããå§ããã®ã§.mailmap
ã®ä»çµã¿ã¯å©çšããRubyãçšããŠéçŽãé 匵ã£ãŠã¿ãããšæããŸãã
幎åäœã§ã³ãããæ°ãã«ãŠã³ãããŠã¿ã
åç¯ã§1998幎ãã2019幎ãŸã§ã®ã³ãããæ°ãéèšããŸãããã幎åäœã§å¯èŠåãè¡ãããã¹ã¯ãªããã§å¹Žããšã®ã³ãããæ°ã®ãã°ãäœæããŸããäœæãããã°ã¯ïŒçš®é¡ãã£ãŠ1998幎ããã®çŽ¯ç©ã®ã³ãããæ°ã幎åäœã§éèšããtotal
ãã°ãšå幎ã®ã³ãããæ°ãéèšããtrend
ãã°ã§ãã
以äžã®Rubyã¹ã¯ãªããã§ã¯1998幎ãã2019幎ãŸã§ã«ãŒãã§system
é¢æ°ã§git shortlog
ãåŒã³åºããŠãªãã€ã¬ã¯ãã§å幎ããšã®ã³ãããæ°ã®ãã°ãã¡ã€ã«ãäœæããŠããŸãã
(1998..2019).each do |e|
system("git shortlog -sne --no-merges --since='#{e}-01-01' --until='#{e}-12-31' > trend/#{e}.log")
system("git shortlog -sne --no-merges --since='1998-01-01' --until='#{e}-12-31' > total/#{e}.log")
end
totalãã°ãèŠãã°ç·åçã«æŽ»èºããã³ããã¿ãŒã®å€åãå¯èŠåã§ããtrendãã°ãå¯èŠåããã°ãã®å¹Žã«æŽ»èºããã³ããã¿ãŒãå¯èŠåããããšãã§ããŸãã
ããŒã¿ã®ååŠçã®ããã®åºç€ãæŽãã
ããŠã幎åäœã®ã³ãããæ°ãååŸããŠãã°ã«åºåããã®ã§æ¬¡ã«è¡ãã¹ãã¯ãããŒã¿ã®å¯èŠåãè¡ãFlourishãèªã¿èŸŒããããŒã¿åœ¢åŒã«ãã°ãå€æããããšã§ãããã®ãããªåŠçã¯äžè¬çã«ãååŠçããšåŒã°ããŸããåè¿°ã®ãªããžããªãããã°ãæœåºããåŠçãšååŠçãšããŒã¿ç»é²ã®äœæ¥ãåãããŠETL(Extract/Transrom/Load)åŠçãšåŒã°ããããšãå€ãã§ãã
ååŠçã®ããŒã«ãšããŠæãããå©çšãããŠããã®ã¯Excelã ãšæãããŸããããŒã¿ãµã€ãšã³ãã£ã¹ãã®æ¹ãªãJupyter NotebookãšPythonã®çµã¿åãããå€ããããããŸããããã®ä»ã«ãå°çšã®ETLããŒã«ã¯æ°å€ãååšããŸãããããä»åã¯ãªãã¹ãRubyã䜿ã£ãŠäœæ¥ãè¡ããšãã趣æšãªã®ã§ãJupyterLab(Jupyter Notebookã®åŸç¶)ãšRubyãå©çšããŠååŠçãè¡ã£ãŠã¿ãããšæããŸãã
ç°å¢æ§ç¯æ¹æ³ãéžæãã
JupyterLab
ãšRubyã®ç°å¢ãæ§ç¯ããã«ã¯ä»¥äžã®ãããªæ§ã
ãªæ¹æ³ããããŸããã©ããäžé·äžçãããŸãããä»åã¯Dockerã䜿ã£ãŠæ§ç¯ããŠã¿ãŸãã
- ããŒã«ã«ã«ç°å¢ãæ§ç¯ãã
- Anacondaã䜿ã£ãŠæã£åãæ©ãæ§ç¯ã§ãã
- ããŒã«ã«ç°å¢ãæ±ãã
- VMäžã«ç°å¢ãæ§ç¯ãã
- Anacondaã䜿ã£ãŠæã£åãæ©ãæ§ç¯ã§ãã
- ããŒã«ã«ç°å¢ã¯æ±ããªããOSã€ã³ã¹ããŒã«ãããªã®ã§æéãããã
- ã³ã³ããã䜿ã£ãŠç°å¢ãæ§ç¯ãã
- æ¢åã®ã³ã³ããã€ã¡ãŒãžãããŒã¹ã«æã£åãæ©ãæ§ç¯ã§ãã
- Dockerç°å¢ã®æ§ç¯ãšDockerfileã®æºåãå¿ èŠ
- ã¯ã©ãŠãäžã®ãããŒãžãã»ãµãŒãã¹ãå©çšãã
- ã¯ã©ãŠãäžã®ããŒãããã¯ã䜿ã£ãŠæ°è»œã«å§ãããã
- ç°å¢ã®èªç±åºŠãäœã
Dockerfileã®æºå
以äžãäœæããDockerfileã§ããããŒã¹ã«ããã³ã³ããã€ã¡ãŒãžã¯ã14èšèªãã¶ã¡èŸŒãã Jupyter Labã®Dockerã€ã¡ãŒãžãäœã£ãŠã¿ããã§å ¬éãããŠããããŒã¹ã€ã¡ãŒãžãå ã«Rubyã ããæ®ããŠãJupyterLabã®èšå®ãæ¡åŒµãå ¥ããããå¿ èŠãªRubyGemsãå ¥ãããã®ã«ãªããŸãã
Dockerfileã®ãã€ã³ãã¯ãinstall Rubyãã®ã³ã¡ã³ãã§å§ãŸãäžé£ã®åŠçã«ãªããŸããããã§Rubyãruby-buildã§ãã«ãããŠãJupyterLabããRubyãéžæããŠèµ·åã§ããããã«Rubyã«ãŒãã«ãgemã§ã€ã³ã¹ããŒã«ããŠããŸãã
FROM hero/jupyter-langs:python
RUN apt-get update && apt-get install -y curl vim
RUN conda install -c conda-forge nodejs
# install Ruby
ENV RUBY_VERSION=2.6.5 \
RUBY_HOME=/opt/ruby
RUN git clone https://github.com/rbenv/ruby-build.git \
&& PREFIX=/usr/local ./ruby-build/install.sh \
&& mkdir -p ${RUBY_HOME} \
&& ruby-build ${RUBY_VERSION} ${RUBY_HOME}/${RUBY_VERSION}
ENV PATH=${RUBY_HOME}/${RUBY_VERSION}/bin:$PATH
RUN gem install --no-document \
benchmark_driver \
cztop \
iruby \
&& iruby register --force
# copy JupyterLab Settings
RUN mkdir -p /root/.jupyter/lab/user-settings
COPY user-settings/ /root/.jupyter/lab/user-settings/
# install favorite jupyter lab extensions
RUN jupyter labextension install @lckr/jupyterlab_variableinspector
RUN jupyter labextension install @jupyterlab/toc
RUN jupyter labextension install @jupyterlab/git
RUN pip install jupyterlab-git
RUN jupyter serverextension enable --py jupyterlab_git
RUN jupyter labextension install jupyterlab-drawio
# for JupyterLab Terminal
ENV SHELL /bin/bash
RUN echo "alias ls='ls --color=auto'" >> /root/.bashrc
RUN echo "export PATH=/root/anaconda3/bin:$PATH" >> /root/.bashrc
RUN echo "export PS1='\u:\W# '" >> /root/.bashrc
# install favorite gems
RUN gem install nokogiri
RUN gem install daru
RUN gem install daru-view
RUN gem install --pre pycall
RUN gem install --pre matplotlib
RUN gem install numpy
RUN gem install pandas
èŠãŠã®éãRubyã¯2.6.5ãå©çšããŠããŸãã2.7.0-rc2ãè©ŠããŠã¿ãã®ã§ãããããŸãåäœããªãã£ãã®ã§æ念ããŸãããDockerãã¡ã€ã«ã¯GitHubã«pushããŠããã®ã§ãå©çšãã ããã
JupyterLabã®èµ·åç»é¢
以äžãå®éã®èµ·åç»é¢ã«ãªããŸããããŒãã¯èªåã®è¶£å³ã§ããŒã¯ã«ããŠãããŸãã
JupyterLabãšRubyã§ããŒã¿ã®ååŠçãè¡ã£ãŠã¿ã
åºæ¬çã«ã¯PyCallãšpandasãçšããŠäœæ¥ããŸããPyCallãRubyããPythonãåŒã³åºããã©ã€ãã©ãªã§ãpandasã¯Pythonã§äž»ã«ããŒã¿ãã¬ãŒã ãæ±ãããã®ã©ã€ãã©ãªã§ãã
ããŒã¿ãã¬ãŒã ãçšãããšExcelã®ããã«è¡šåœ¢åŒã®ããŒã¿ãæ±ãããããªããŸãã
Rubyã³ããã¿ã®åå¯ããè¡ã£ãŠã¿ã
ããããã®äœæ¥ã¯ããŒãããã¯ãçšããŠäœæ¥ããŸãããããŒãããã¯ãçŽæ¥è¡šç€ºã¯ã§ããªãã®ã§æç²ããŠèª¬æããŸãã
ãŸãã¯ãã©ã€ãã©ãªãèªã¿èŸŒã¿ãŸãããŸãPyCallã®ãã䜿ãå€æ°ã¯ã·ã§ãŒãã«ãããå®çŸ©ããŠãããšäŸ¿å©ã§ãã以äžã§ã¯Pythonã®çµã¿èŸŒã¿é¢æ°ã¯PyCall::builtins
ã«å®çŸ©ãããŠããã®ã§pyblt
ã«æ ŒçŽããŠããŸãã
require 'open-uri'
require 'pycall/import'
include PyCall::Import
pyimport :pandas, as: :pd
pyimport :numpy, as: :np
pyblt = PyCall::builtins
Dict = PyCall::Dict
List = PyCall::List
次ã«ã³ããã¿ãŒãã°(åè¿°ã®git shortlog
ã§äœæãã1998幎ãã2019幎ãŸã§ã®äœè
å¥ã³ãããæ°)ãèªã¿èŸŒãã§ããŒã¿ãã¬ãŒã ãäœæããŸãã
read_committers_log
é¢æ°ã¯ã³ããã¿ãŒãã°ãããŒã¹ããŠãã³ãããæ°ãšäœè
ãšEã¡ãŒã«ã¢ãã¬ã¹ã«åå²ããŠããŒã¿ãã¬ãŒã ãäœæããŠããŸãã
def read_committers_log(file)
committers = File.read(file).split("\n").map do |e|
commits, id = e.split("\t")
user, addr = id.split(" <")
[commits.to_i, user, addr.chop]
end
pd.DataFrame.new(data: committers, columns:[:commits, :author, :addr])
end
df = read_committers_log('ruby_committers.log')
次ã«åå¯ãã®æŠç¥ãšããŠäœè
(author
)ãååã®ãã®ã¯åäžäººç©ã ãšä»®å®ããŠã©ãã ãåå¯ãã§ããã確èªããŸããããã§284ãã267ãŸã§åå¯ãã§ããããšã確èªããŸããã
df.author.unique().size
ãããŠå®éã«author
ã§åå¯ããè¡ããŸãã以äžã¯author
ã§groupby
ããããšãã³ãããæ°ãåèšããEã¡ãŒã«ã¢ãã¬ã¹ã¯ã«ã³ããæãã§çµåããŠãã³ãããæ°ã§ãœãŒãããããšã€ã³ããã¯ã¹ããªã»ããããŠããŸãã
pandasã®éçŽé¢æ°ã®agg
ã«ã¯èŸæžãæ瀺çã«æž¡ãå¿
èŠããããŸããæåã¯ããã«Rubyã®ããã·ã¥ããã®ãŸãŸæž¡ããŠããŠåããªããŠæ©ã¿ãŸããããŸããPythonã§Lambdaé¢æ°ãæž¡ãç®æã«ã¯Procãªããžã§ã¯ããæž¡ãå¿
èŠããããŸãããRubyã®Lambdaã§ã¯åããŸããã§ããããããPyCallã®ä»æ§ãã©ããã¯ããŸãæéããªãã£ãã®ã§èª¿ã¹ãããŠããŸããã»ã»ã»
addr_join = proc {|s| s.tolist.to_a.join(',')}
df_uniq_author = df.groupby(:author).agg(Dict.new({commits: :sum, addr: addr_join}))
.sort_values(:commits, ascending: false).reset_index
äœè
åã®æ¬¡ã®åå¯ãã¯ã¡ãŒã«ã¢ãã¬ã¹ã®å
é éšå(@
ããåã®éšå)ãçšããŸããããã®æŠç¥ã¯ééã確çãé«ãå±éºãªæ¹æ³ã§ããããšããããééã£ãç®æã¯åå¥ã«å¯ŸåŠããããšã«ããŠå®è¡ããŸããã
以äžã®ã³ãŒãã¯ã¡ãŒã«ã¢ãã¬ã¹ã®å
é éšåãæãåºããããŒã¿ãã¬ãŒã ã®æåŸã«addr_user
ãšããŠè¿œå ããã³ãŒãã§ãã
è©Šè¡é¯èª€ããªããç¹æ®ãªå ŽååããããŠããŸããé¢çœãã®ã¯matzbot
ã®ååšã§ãããã®ãããã¯æ¯æ¥å®æçã«ã«version.h
ã®RUBY_RELEASE_DAY
ãæžãæãããä»äºãããŠããããã§ãã
addr_user = proc do |df|
df.addr.tolist.map do |addrs|
addrs.split(',').map do |addr|
user, domain = addr.split('@')
if user == 'mail'
domain.split('.')[0]
elsif ['svn', 'svn-admin'].include?(user)
'matzbot'
elsif domain == 'users.noreply.github.com'
sp = user.split('+')
if sp.size == 2
sp[1]
else
sp[0]
end
else
user
end
end.uniq.join(',')
end
end
df_addr_user = df_uniq_author.assign(addr_user: addr_user)
次ã®ã³ãŒãã¯å®éã«addr_user
ã§åå¯ããè¡ã£ãŠããŸããäœè
å(author
)ã®éçŽã«ã¯æååãé·ãæ¹ãæ¡çšããŠããŸããäžè¬çã«æåã¯çããŠãŒã¶åãçšããŠãããåŸããæ¬åãauthor
ã«èšå®ããæ¹ãå€ãããããã§ãã
max_author = proc {|s| s.tolist.max_by{|e| e.size}}
df_uniq_addr_user = df_addr_user.groupby(:addr_user).agg(Dict.new({commits: :sum, addr: addr_join, author: max_author}))
.sort_values(:commits, ascending: false).reset_index
次ã«åå¯ããããŠãŒã¶åãGitHubã«ååšããã確èªããŸããããã¯æçµçã«GitHubã®ãŠãŒã¶åããŠããŒã¯ãªããŒã«ããŠãGitHubã®ã¢ãã¿ãŒãå¯èŠåã«çšãããããã§ãã
def check_github_user(user)
open("https://github.com/#{user}/")
true
rescue => e
false
end
is_github_user = df_uniq_addr_user.addr_user.tolist.map do |e|
sleep(1)ã# è² è·ããããããªãããã«ãã
check_github_user(e)
end
df_github_user = df_uniq_addr_user.assign(is_github_user: is_github_user)
以äžã®ã³ãŒãã¯GitHubãŠãŒã¶ãèŠã€ãã£ãå Žåã¯ãã®ãŸãŸãaddr_user
ããã®ãŸãŸåºåããããã§ãªãå Žåã¯å
é ã«XXXX_
ãä»å ããæååãtmp_user
ãšããŠåã«è¿œå ããŸãã
add_tmp_user = proc do |df|
df.is_github_user.tolist.zip(df.addr_user.tolist).map do |is_github_user, addr_user|
is_github_user ? addr_user : "XXXX_" + addr_user
end
end
df_tmp_user = df_github_user.assign(tmp_user: add_tmp_user)
df_mod_drop = df_tmp_user.drop(columns: [:addr_user])
æåŸã«åã®äžŠã³ãreindex
ã§æŽçããŠäžæãã¡ã€ã«ãšããŠCSV圢åŒã§ä¿åããŸãã
df_tmp_out = df_mod_drop.reindex(columns: [:commits, :tmp_user, :author, :is_github_user, :addr])
.sort_values([:commits, :tmp_user], ascending: [false, true]).reset_index(drop: true)
df_tmp_out.to_csv("ruby_committers_tmp.csv", index: false)
ãããŸã§ã§ããããåå¯ãã®ç¬¬äžæ®µéãããã£ããšããã§ãããããŸã§ã®äœæ¥çµæã¯ä»¥äžã®ããŒãããã¯ã§ç¢ºèªã§ããŸãã
ãã®åŸã¯äœè åãããŒã«ããŠGoogleã§æ€çŽ¢ããããŠnokogiriã§ã¹ã¯ã¬ã€ãã³ã°ãããŠGitHubãŠãŒã¶åã®åè£ãåºåãããããªããšãããŠåå¯ãã®ç²ŸåºŠãé«ãããããŸããããçµå±æåŸã¯äººåã§é 匵ããŸããã
åå¯ãã®çµæã¯ä»¥äžã«ã³ãããããã®ã§ééã£ãŠãããã€ã·ã¥ãŒããã«ãªã¯ã§ãç¥ããé ãããšå¹žãã§ãã
æçµçãªéèšããŒãã«ãäœæãã
ããããåå¯ããè¡ã£ãã³ããã¿ãŒã®ãã¹ã¿ãŒããŒãã«ãå®æããã®ã§ããããããšã«å¹Žåäœã§éèšãããã°ãFlourishãèªã¿èŸŒããããŒã¿ã«å€æããŸãã
以äžã®ã³ãŒãã¯ã³ããã¿ãŒã®ãã¹ã¿ãŒããŒãã«ã«ã³ãããæ°ã«å¿ããŠã³ãããã©ã³ã¯ãã€ããŠããŸããã³ãããã©ã³ã¯ã¯ä»¥äžã®çšã«ãªã£ãŠããŸãã
ã©ã³ã¯ã¯å®å
šã«èªåã®äž»èŠ³ã§ããã¶ã£ã¡ããåºåãã®ãããšããã§åºåã£ãŠã¿ãã ãã§ãã
ã©ã³ã¯ | ã³ãããæ° | 説æ |
---|---|---|
C | 10æªæº | åçŽè |
B | 10以äž100æªæº | äžçŽè |
A | 100以äž1000æªæº | äžçŽè |
S | 1000以äž10000æªæº | è¶ äºº |
SS | 10000ä»¥äž | ç¥ |
df_committers = pd.read_csv('ruby_committers.csv')
def add_rank(df_committers)
df_all = read_committers_log("ruby_committers.log")
commits = df_all[:commits].tolist
addr = df_all[:addr].tolist
committers = Hash.new(0)
commits.zip(addr).each do |commits, addr|
addr_replaced = addr.gsub('+', '.')
user = df_committers[proc {|df| df.addr.str.contains(addr_replaced)}].user.tolist.first
if user
committers[user] += commits
else
p addr unless addr.start_with?('(no author)')
end
end
users = df_committers.user.tolist.to_a
rank_list = users.map do |user|
committers.fetch(user, 0)
end.map do |commits|
if commits >= 10000
"SS"
elsif commits >= 1000
"S"
elsif commits >= 100
"A"
elsif commits >= 10
"B"
else
"C"
end
end
df_committers[:rank] = rank_list
df_committers
end
add_rank(df_committers)
次ã®ã³ãŒãã¯å¹Žåäœã§éèšããããŒã¿ããã¹ã¿ãŒããŒã¿ã䜿ã£ãŠéçŽããŠããŸããéçŽã¯ãã¹ã¿ãŒããŒã¿ã®addr
æ¬ã®ã¡ãŒã«ã¢ãã¬ã¹ã«å¯Ÿè±¡ã®ã¡ãŒã«ã¢ãã¬ã¹ãéšåæååãšããŠå«ãŸããŠãããã©ããã§å€æããŠããŸãã
years = (1998..2019)
activity_type = 'trend'
commits_by_years = years.map do |year|
df_year = read_committers_log("#{activity_type}/#{year}.log")
commits = df_year[:commits].tolist
addr = df_year[:addr].tolist
commits_by_year = Hash.new(0)
commits.zip(addr).each do |commits, addr|
addr_replaced = addr.gsub('+', '.')
user = df_committers[proc {|df| df.addr.str.contains(addr_replaced)}].user.tolist.first
if user
commits_by_year[user] += commits
else
p addr unless addr.start_with?('(no author)')
end
end
commits_by_year
end
nil
以äžã®ã³ãŒãã¯æ°ããªåãšããŠGitHubã®ãŠãŒã¶ã®å Žåã¯ã¢ãã¿ãŒã®URLãimage
åãšããŠè¿œå ãããŸããŠãŒã¶åãšäœè
åãçµåããlabel
åãä»å ããŠããŸãã
label_add = proc do |df|
df.user.tolist.zip(df.author.tolist).map do |user, author|
user == author ? user : "#{user} (#{author})"
end
end
image_add = proc do |df|
df.user.tolist.zip(df.is_github_user.tolist).map do |user, is_github_user|
is_github_user ? "https://github.com/#{user}.png" : ''
end
end
df_committers_added = df_committers.assign(label: label_add, image: image_add)
次ã®ã³ãŒãã§æçµçãªããŒãã«ãäœæããŠããŸããå ·äœçã«ã¯åãšããŠ1998幎ãã2019幎ãŸã§ã®22åãè¿œå ããŠããŸãã
df_development_activity = df_committers_added
users = df_development_activity.user.tolist.to_a
years.zip(commits_by_years).each do |year, commits_by_year|
commits_list = users.map do |user|
commits_by_year.fetch(user, 0)
end
df_development_activity[year] = commits_list
end
df_development_activity.to_csv("ruby_development_activity_#{activity_type}_1998-2019.csv", index: false)
ãããŸã§ã®äœæ¥çµæã¯ä»¥äžã®ããŒãããã¯ã§ç¢ºèªã§ããŸãã
ãŸãåºåçµæã¯ä»¥äžã®ãã¡ã€ã«ã«ãªããŸãã
Flourishã§å¯èŠåããŠã¿ã
Flourishã¯éåžžã«å€ãã®å¯èŠåã«å¯Ÿå¿ããŠããŸãããä»åã¯Bar chart raceãçšããŠããŸãã
ããŒã¿ããåºæ¥ãŠããã°å¯èŠåã¯éåžžã«ç°¡åã§ãCSVãã¡ã€ã«ãã¢ããããŒãããŠå¯èŠåã«çšããåãéžæããã ãã§ãã
å®æããå¯èŠå
以äžãå®æããå¯èŠåã§ããäžå€®ã®Rubyã®ç»åã¯RubyããŒã ããŒãžããåŒçšããŠãããäœè
ã®ç»åã¯GitHubããåŒçšããŠãããŸã2ã
以äžã¯1998幎ããã®çŽ¯èšã³ãããæ°ã®ãã£ãŒãã§ãã
以äžã¯å¹Žåäœã®ã³ãããæ°ã®å¯èŠåã§ãããã®å¹Žã«æŽ»èºããã³ããã¿ãŒãåãããšæããŸãã
ãŸãšã
èŠãŠã®ãšããã³ãããæ°1äžä»¶è¶ ãã®nobuãããå§åçã§ãã äžäººSSã©ã³ã¯ã«ãªã£ãŠããŸãããããŠRubyäœè ã®matzããã¯æè¿ã¯Rubyæ¬äœã«ã¯ããŸãã³ããããããŠããªãããã§ããæããmrubyã®éçºçã§ãå€å¿ãªã®ã ãšæããŸããããšå¯èŠåã«é¢ããŠèšãã°ãRubyéçºã®æåã®5幎éã¯ã³ããããã°ããªãã®ã§å¯èŠåã§ããŠããªãã®ãšãã³ããã¿ãŒã«ãã£ãŠä»£çã§ã³ããããããåããªãäœè ãå€æ°ãããšæãããã®ã§ããã®å¯èŠåã¯ãããã£ãäžå®å šãªé¢ãããããšããç解é ããäžã§ã芧ãã ããã
èŠåŽããç¹ã¯å€ã ãããŸããããã¯ããã³ããã§åå¯ãã«èŠåŽããŸãããRubyã¯æŽå²ãé·ãã³ããã¿ãŒã®æ°ãå€ãã®ã§åå¯ããããŸãè¡ããªãã±ãŒã¹ãå€çºããŸããã
ä»åGitHubã®ã¢ãã¿ãŒç»åãåºãé¢ä¿ããæçµçã«ã¯GitHubã®ãŠãŒã¶ãŒåã§åå¯ããè¡ããŸãããããããã©ã€ãšã¿ãªãªGitHubãå«ãæ¹ãRubyã®éçºããçªåŠæ¶ããæ¹ã倧åæã«ã³ããããé絶ããæ¹ãªã©ã§GitHubã¢ã«ãŠã³ããèŠã€ããããªãã£ãæ¹ãäœäººãããŸããããããèŠåŽããåãã®ãããªRubyã®éçºå²ãå£éèŠãããšãã§ããã®ã§ãšãŠãé¢çœãã£ãã§ãã
æ¬èšäºãRuby2.7ã®ãªãªãŒã¹ãšãšãã«ãRubyãæãã人éãžã®ãããããªã¯ãªã¹ãã¹ãã¬ãŒã³ãã«ãªãã°å¹žãã§ãã
Rubyã®22幎ã«æž¡ãã³ãããã®æŽå²ãå¯èŠåããŠã¿ãŸãããRubyãæããæ¹ãã¡ãžã®ã¯ãªã¹ãã¹ãã¬ãŒã³ãã«ãªãã°å¹žãã§ãã#Ruby pic.twitter.com/wrDu6UXcTh
â hinastory (@hinastory999) December 24, 2019
-
詳现ã¯Rubyãªããžããªã¬ã€ããåç §ããŠãã ããã â©
-
åŒçšèªäœã¯ãã§ã¢ãŠãŒã¹ã®ç¯å²å ã ãšå人çã«ã¯æã£ãŠããŸããäœãåé¡ãããã°ãææãã ããã â©